Skip to content

Instantly share code, notes, and snippets.

@iMartyn
Created November 1, 2015 21:05
Show Gist options
  • Save iMartyn/015ff0f1ea20d5fa9b8f to your computer and use it in GitHub Desktop.
Save iMartyn/015ff0f1ea20d5fa9b8f to your computer and use it in GitHub Desktop.
#!/bin/bash
usage() {
echo "Find the true writable size of a device in mb. Useful for cheap/fake"
echo "SD Cards, mp3 players etc. that have been missold."
echo "NOTE: the data on the device WILL be destroyed"
echo ""
echo "Options:"
echo ""
echo " -h|-?|--help Show this help text"
echo " -d /dev/something Destination device"
echo " -v Be verbose about what is currently being done"
echo " -f /some/file Use this source file (1M file) instead of random data"
echo " -m maxsize Specify the max size (e.g. -m 48) that you want to test to"
echo " otherwise, size of device reported is assumed"
echo " -s startsize Specify where you want to start (e.g. -m 129) in meg"
echo " -p Print chars whilst working. W=write, R=read, .=comparing, -=no error."
echo " -2 Spot check at 1M, 2M, 4M, 8M, 16M etc."
echo " Recommendation, do this and then rerun starting from half of"
echo " where it reached, i.e. if it says it's a 32M device,"
echo " rerun with -s16 without the -2 or try -s30 in case it's close."
exit 1
}
verbecho() {
if [ "${verbose}" != "0" ]; then
echo $*
fi
}
verbose=0
verbout=/dev/null
sourcefile=""
device=""
force=0
maxsize=0
startsize=0
semiverbose=0
spotcheck=0
OPTIND=1
while getopts "h?pv2d:f:-:m:s:" opt; do
case "${opt}" in
-) case "${OPTARG}" in
help)
usage
exit 0
;;
force)
force=1
;;
*)
echo "Could not parse long arg --${OPTARG}"
exit 1
;;
esac;;
h|\?)
usage
exit 0
;;
v) echo verbose mode set
verbose=1
verbout=`tty`
;;
f) sourcefile=$OPTARG
;;
d) devicefile=$OPTARG
;;
m) maxsize=$OPTARG
;;
s) startsize=$OPTARG
;;
p) semiverbose=1
;;
2) spotcheck=1
;;
esac
done
if [ "${devicefile}" == "" ]; then
echo ""
echo ""
echo "Find the real space of WHAT?!"
echo ""
echo "USAGE:"
usage
exit 0
fi
shift $((OPTIND-1))
[ "$1" = "--" ] && shift
if [ "`whoami`" != "root" ]; then
echo "You need to be root for this script to work."
exit 3
fi
if grep "^$devicefile" /proc/mounts > /dev/null 2>&1; then
echo "Device is mounted. Won't continue."
exit 4
fi
createsourcefile() {
if [ "$1" == "" ]; then
sourcesource=/dev/urandom
else
sourcesource=$1
fi
pushd /tmp/ 2>&1 > /dev/null
sourcefile=/tmp/`mktemp realsize.XXXXXXXX`
popd 2>&1 > /dev/null
dd if=$sourcesource of=$sourcefile bs=1M count=1 >$verbout 2>&1
sourcefilecreated=1
}
sourcefilecreated=0
if [ "${sourcefile}" == "" ]; then
verbecho "Source file not set, creating.."
createsourcefile
fi
# Check the file exists and is the right size
if [ ! -f $sourcefile ]; then
echo "File $sourcefile does not exist, bailing."
exit 5
fi
sourcefilesize=`stat ${sourcefile} | grep Size | cut -f4 -d" "`
if [ $sourcefilesize -lt 1048576 ]; then
echo "Cannot work with a file of less than 1M (1048576 bytes)"
exit 6
fi
if [ $sourcefilesize -gt 1048576 ]; then
echo "WARN: you have passed a file greater than 1M, I would have to create a 1M file from your file"
if [ "${force}" == "0" ]; then
echo "Bailing because you didn't give a good file -- did you get source and dest the wrong way round?"
echo " use --force if you are certain."
exit 7
fi
echo "WARN: you used force, so I'm going to beleive you and create a 1M file of the source file you passed."
originalsource=$sourcefile
createsourcefile $originalsource
fi
if [ $maxsize -lt 1 ]; then
maxsizebytes=`blockdev --getsize64 ${devicefile}`
if [ $? -ne 0 ]; then
echo "Could not determine size of destination ${devicefile}"
exit 8
fi
maxsize=`expr $maxsizebytes / 1024 / 1024`
fi
if [ $maxsize -lt $startsize ]; then
echo "Max size of ${maxsize} is less than Start size of ${startsize}. I can't help you here!"
exit 9
fi
currentmeg=$startsize
megforfailure=-1
writeameg() {
dd if=$sourcefile of=$devicefile bs=1M count=1 seek=$1 >$verbout 2>&1
}
readameg() {
# should only be used from /tmp
thismeg=`mktemp realsize-block.XXXXXXXX`
if [ $semiverbose -gt 0 ]; then
echo -n -e "\bR"
fi
dd if=$devicefile bs=1M skip=$1 count=1 of=$thismeg >$verbout 2>&1
verbecho "dd if=$devicefile bs=1M skip=$1 count=1 of=$thismeg >$verbout 2>&1"
if [ $semiverbose -gt 0 ]; then
echo -n -e "\b."
fi
diff $thismeg $sourcefile >$verbout 2>&1
if [ $? -gt 0 ]; then
verbecho "We found a block that didn't match!"
megforfailure=$currentmeg
if [ $semiverbose -gt 0 ]; then
echo -n -e "\bX"
fi
else
if [ $semiverbose -gt 0 ]; then
echo -n -e "\b-"
fi
fi
rm $thismeg
}
pushd /tmp > /dev/null 2>&1
while [ $megforfailure -lt 0 ]; do
if [ $semiverbose -gt 0 ]; then
echo -n "W"
fi
writeameg $currentmeg
readameg $currentmeg
if [ $megforfailure -gt 0 ]; then
popd > /dev/null 2>&1
if [ $semiverbose -gt 0 ]; then
echo ""
fi
echo "Size of device found : ${megforfailure}M";
cleanup
exit 99
fi
if [ $spotcheck -gt 0 ]; then
if [ $currentmeg -eq 0 ]; then
currentmeg=1
fi
currentmeg=`expr $currentmeg \* 2`
echo "now at $currentmeg"
else
currentmeg=`expr $currentmeg + 1`
fi
if [ $currentmeg -eq $maxsize ]; then
break;
fi
done
popd > /dev/null 2>&1
if [ $semiverbose -gt 0 ]; then
echo ""
fi
echo "Looks to be the same size as reported to the kernel, or bigger than you specified we should test to."
cleanup(){
if [ "${sourcefilecreated}" != "0" ]; then
rm ${sourcefile}
fi
}
cleanup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment