You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
7.1 KiB
282 lines
7.1 KiB
#!/bin/bash
|
|
#
|
|
# Copyright (C) 2010 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
# mkobb.sh - Creates OBB files on Linux machines
|
|
|
|
# Directory where we should temporarily mount the OBB loopback to copy files
|
|
MOUNTDIR=/tmp
|
|
|
|
# Presets. Changing these will probably break your OBB on the device
|
|
CRYPTO=twofish
|
|
FS=vfat
|
|
MKFS=mkfs.vfat
|
|
LOSETUP=losetup
|
|
BLOCK_SIZE=512
|
|
SLOP=512 # Amount of filesystem slop in ${BLOCK_SIZE} blocks
|
|
|
|
find_binaries() {
|
|
MKFSBIN=`which ${MKFS}`
|
|
LOSETUPBIN=`which ${LOSETUP}`
|
|
MOUNTBIN=`which mount`
|
|
UMOUNTBIN=`which umount`
|
|
DDBIN=`which dd`
|
|
RSYNCBIN=`which rsync`
|
|
PBKDF2GEN=`which pbkdf2gen`
|
|
}
|
|
|
|
check_prereqs() {
|
|
if [ "`uname -s`x" != "Linuxx" ]; then \
|
|
echo "ERROR: This script only works on Linux!"
|
|
exit 1
|
|
fi
|
|
|
|
if ! egrep -q "^cryptoloop " /proc/modules; then \
|
|
echo "ERROR: Could not find cryptoloop in the kernel."
|
|
echo "Perhaps you need to: modprobe cryptoloop"
|
|
exit 1
|
|
fi
|
|
|
|
if ! egrep -q "name\s*:\s*${CRYPTO}$" /proc/crypto; then \
|
|
echo "ERROR: Could not find crypto \`${CRYPTO}' in the kernel."
|
|
echo "Perhaps you need to: modprobe ${CRYPTO}"
|
|
exit 1
|
|
fi
|
|
|
|
if ! egrep -q "^\s*${FS}$" /proc/filesystems; then \
|
|
echo "ERROR: Could not find filesystem \`${FS}' in the kernel."
|
|
echo "Perhaps you need to: modprobe ${FS}"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "${MKFSBIN}x" = "x" ]; then \
|
|
echo "ERROR: Could not find ${MKFS} in your path!"
|
|
exit 1
|
|
elif [ ! -x "${MKFSBIN}" ]; then \
|
|
echo "ERROR: ${MKFSBIN} is not executable!"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "${LOSETUPBIN}x" = "x" ]; then \
|
|
echo "ERROR: Could not find ${LOSETUP} in your path!"
|
|
exit 1
|
|
elif [ ! -x "${LOSETUPBIN}" ]; then \
|
|
echo "ERROR: ${LOSETUPBIN} is not executable!"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "${PBKDF2GEN}x" = "x" ]; then \
|
|
echo "ERROR: Could not find pbkdf2gen in your path!"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
cleanup() {
|
|
if [ "${loopdev}x" != "x" ]; then \
|
|
${LOSETUPBIN} -d ${loopdev}
|
|
fi
|
|
}
|
|
|
|
hidden_prompt() {
|
|
unset output
|
|
prompt="$1"
|
|
outvar="$2"
|
|
while read -s -n 1 -p "$prompt" c; do \
|
|
if [ "x$c" = "x" ]; then \
|
|
break
|
|
fi
|
|
prompt='*'
|
|
output="${output}${c}"
|
|
done
|
|
echo
|
|
eval $outvar="$output"
|
|
unset output
|
|
}
|
|
|
|
read_key() {
|
|
hidden_prompt " Encryption key: " key
|
|
|
|
if [ "${key}x" = "x" ]; then \
|
|
echo "ERROR: An empty key is not allowed!"
|
|
exit 1
|
|
fi
|
|
|
|
hidden_prompt "Encryption key (again): " key2
|
|
|
|
if [ "${key}x" != "${key2}x" ]; then \
|
|
echo "ERROR: Encryption keys do not match!"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
onexit() {
|
|
if [ "x${temp_mount}" != "x" ]; then \
|
|
${UMOUNTBIN} ${temp_mount}
|
|
rmdir ${temp_mount}
|
|
fi
|
|
if [ "x${loop_dev}" != "x" ]; then \
|
|
if [ ${use_crypto} -eq 1 ]; then \
|
|
dmsetup remove -f ${loop_dev}
|
|
${LOSETUPBIN} -d ${old_loop_dev}
|
|
else \
|
|
${LOSETUPBIN} -d ${loop_dev}
|
|
fi
|
|
fi
|
|
if [ "x${tempfile}" != "x" -a -f "${tempfile}" ]; then \
|
|
rm -f ${tempfile}
|
|
fi
|
|
if [ "x${keyfile}" != "x" -a -f "${keyfile}" ]; then \
|
|
rm -f ${keyfile}
|
|
fi
|
|
echo "Fatal error."
|
|
exit 1
|
|
}
|
|
|
|
usage() {
|
|
echo "mkobb.sh -- Create OBB files for use on Android"
|
|
echo ""
|
|
echo " -d <directory> Use <directory> as input for OBB files"
|
|
echo " -k <key> Use <key> to encrypt OBB file"
|
|
echo " -K Prompt for key to encrypt OBB file"
|
|
echo " -o <filename> Write OBB file out to <filename>"
|
|
echo " -v Verbose mode"
|
|
echo " -h Help; this usage screen"
|
|
}
|
|
|
|
find_binaries
|
|
check_prereqs
|
|
|
|
use_crypto=0
|
|
|
|
args=`getopt -o d:hk:Ko:v -- "$@"`
|
|
eval set -- "$args"
|
|
|
|
while true; do \
|
|
case "$1" in
|
|
-d) directory=$2; shift 2;;
|
|
-h) usage; exit 1;;
|
|
-k) key=$2; use_crypto=1; shift 2;;
|
|
-K) prompt_key=1; use_crypto=1; shift;;
|
|
-v) verbose=1; shift;;
|
|
-o) filename=$2; shift 2;;
|
|
--) shift; break;;
|
|
*) echo "ERROR: Invalid argument in option parsing! Cannot recover. Ever."; exit 1;;
|
|
esac
|
|
done
|
|
|
|
if [ "${directory}x" = "x" -o ! -d "${directory}" ]; then \
|
|
echo "ERROR: Must specify valid input directory"
|
|
echo ""
|
|
usage
|
|
exit 1;
|
|
fi
|
|
|
|
if [ "${filename}x" = "x" ]; then \
|
|
echo "ERROR: Must specify filename"
|
|
echo ""
|
|
usage
|
|
exit 1;
|
|
fi
|
|
|
|
if [ ${use_crypto} -eq 1 -a "${key}x" = "x" -a 0${prompt_key} -eq 0 ]; then \
|
|
echo "ERROR: Crypto desired, but no key supplied or requested to prompt for."
|
|
exit 1
|
|
fi
|
|
|
|
if [ 0${prompt_key} -eq 1 ]; then \
|
|
read_key
|
|
fi
|
|
|
|
outdir=`dirname ${filename}`
|
|
if [ ! -d "${outdir}" ]; then \
|
|
echo "ERROR: Output directory does not exist: ${outdir}"
|
|
exit 1
|
|
fi
|
|
|
|
# Make sure we clean up any stuff we create from here on during error conditions
|
|
trap onexit ERR
|
|
|
|
tempfile=$(tempfile -d ${outdir}) || ( echo "ERROR: couldn't create temporary file in ${outdir}"; exit 1 )
|
|
|
|
block_count=`du -s --apparent-size --block-size=512 ${directory} | awk '{ print $1; }'`
|
|
if [ $? -ne 0 ]; then \
|
|
echo "ERROR: Couldn't read size of input directory ${directory}"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Creating temporary file..."
|
|
${DDBIN} if=/dev/zero of=${tempfile} bs=${BLOCK_SIZE} count=$((${block_count} + ${SLOP})) > /dev/null 2>&1
|
|
if [ $? -ne 0 ]; then \
|
|
echo "ERROR: creating temporary file: $?"
|
|
fi
|
|
|
|
loop_dev=$(${LOSETUPBIN} -f) || ( echo "ERROR: losetup wouldn't tell us the next unused device"; exit 1 )
|
|
|
|
${LOSETUPBIN} ${loop_dev} ${tempfile} || ( echo "ERROR: couldn't create loopback device"; exit 1 )
|
|
|
|
if [ ${use_crypto} -eq 1 ]; then \
|
|
eval `${PBKDF2GEN} ${key}`
|
|
unique_dm_name=`basename ${tempfile}`
|
|
echo "0 `blockdev --getsize ${loop_dev}` crypt ${CRYPTO} ${key} 0 ${loop_dev} 0" | dmsetup create ${unique_dm_name}
|
|
old_loop_dev=${loop_dev}
|
|
loop_dev=/dev/mapper/${unique_dm_name}
|
|
fi
|
|
|
|
#
|
|
# Create the filesystem
|
|
#
|
|
echo ""
|
|
${MKFSBIN} -I ${loop_dev}
|
|
echo ""
|
|
|
|
#
|
|
# Make the temporary mount point and mount it
|
|
#
|
|
temp_mount="${MOUNTDIR}/${RANDOM}"
|
|
mkdir ${temp_mount}
|
|
${MOUNTBIN} -t ${FS} -o loop ${loop_dev} ${temp_mount}
|
|
|
|
#
|
|
# rsync the files!
|
|
#
|
|
echo "Copying files:"
|
|
${RSYNCBIN} -av --no-owner --no-group ${directory}/ ${temp_mount}/
|
|
echo ""
|
|
|
|
echo "Successfully created \`${filename}'"
|
|
|
|
if [ ${use_crypto} -eq 1 ]; then \
|
|
echo "salt for use with obbtool is:"
|
|
echo "${salt}"
|
|
fi
|
|
|
|
#
|
|
# Undo all the temporaries
|
|
#
|
|
umount ${temp_mount}
|
|
rmdir ${temp_mount}
|
|
if [ ${use_crypto} -eq 1 ]; then \
|
|
dmsetup remove -f ${loop_dev}
|
|
${LOSETUPBIN} -d ${old_loop_dev}
|
|
else \
|
|
${LOSETUPBIN} -d ${loop_dev}
|
|
fi
|
|
mv ${tempfile} ${filename}
|
|
|
|
trap - ERR
|
|
|
|
exit 0
|