1#!/bin/bash 2# 3# Copyright (C) 2010 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18# mkobb.sh - Creates OBB files on Linux machines 19 20# Directory where we should temporarily mount the OBB loopback to copy files 21MOUNTDIR=/tmp 22 23# Presets. Changing these will probably break your OBB on the device 24CRYPTO=twofish 25FS=vfat 26MKFS=mkfs.vfat 27LOSETUP=losetup 28BLOCK_SIZE=512 29SLOP=512 # Amount of filesystem slop in ${BLOCK_SIZE} blocks 30 31find_binaries() { 32 MKFSBIN=`which ${MKFS}` 33 LOSETUPBIN=`which ${LOSETUP}` 34 MOUNTBIN=`which mount` 35 UMOUNTBIN=`which umount` 36 DDBIN=`which dd` 37 RSYNCBIN=`which rsync` 38 PBKDF2GEN=`which pbkdf2gen` 39} 40 41check_prereqs() { 42 if [ "`uname -s`x" != "Linuxx" ]; then \ 43 echo "ERROR: This script only works on Linux!" 44 exit 1 45 fi 46 47 if ! egrep -q "^cryptoloop " /proc/modules; then \ 48 echo "ERROR: Could not find cryptoloop in the kernel." 49 echo "Perhaps you need to: modprobe cryptoloop" 50 exit 1 51 fi 52 53 if ! egrep -q "name\s*:\s*${CRYPTO}$" /proc/crypto; then \ 54 echo "ERROR: Could not find crypto \`${CRYPTO}' in the kernel." 55 echo "Perhaps you need to: modprobe ${CRYPTO}" 56 exit 1 57 fi 58 59 if ! egrep -q "^\s*${FS}$" /proc/filesystems; then \ 60 echo "ERROR: Could not find filesystem \`${FS}' in the kernel." 61 echo "Perhaps you need to: modprobe ${FS}" 62 exit 1 63 fi 64 65 if [ "${MKFSBIN}x" = "x" ]; then \ 66 echo "ERROR: Could not find ${MKFS} in your path!" 67 exit 1 68 elif [ ! -x "${MKFSBIN}" ]; then \ 69 echo "ERROR: ${MKFSBIN} is not executable!" 70 exit 1 71 fi 72 73 if [ "${LOSETUPBIN}x" = "x" ]; then \ 74 echo "ERROR: Could not find ${LOSETUP} in your path!" 75 exit 1 76 elif [ ! -x "${LOSETUPBIN}" ]; then \ 77 echo "ERROR: ${LOSETUPBIN} is not executable!" 78 exit 1 79 fi 80 81 if [ "${PBKDF2GEN}x" = "x" ]; then \ 82 echo "ERROR: Could not find pbkdf2gen in your path!" 83 exit 1 84 fi 85} 86 87cleanup() { 88 if [ "${loopdev}x" != "x" ]; then \ 89 ${LOSETUPBIN} -d ${loopdev} 90 fi 91} 92 93hidden_prompt() { 94 unset output 95 prompt="$1" 96 outvar="$2" 97 while read -s -n 1 -p "$prompt" c; do \ 98 if [ "x$c" = "x" ]; then \ 99 break 100 fi 101 prompt='*' 102 output="${output}${c}" 103 done 104 echo 105 eval $outvar="$output" 106 unset output 107} 108 109read_key() { 110 hidden_prompt " Encryption key: " key 111 112 if [ "${key}x" = "x" ]; then \ 113 echo "ERROR: An empty key is not allowed!" 114 exit 1 115 fi 116 117 hidden_prompt "Encryption key (again): " key2 118 119 if [ "${key}x" != "${key2}x" ]; then \ 120 echo "ERROR: Encryption keys do not match!" 121 exit 1 122 fi 123} 124 125onexit() { 126 if [ "x${temp_mount}" != "x" ]; then \ 127 ${UMOUNTBIN} ${temp_mount} 128 rmdir ${temp_mount} 129 fi 130 if [ "x${loop_dev}" != "x" ]; then \ 131 if [ ${use_crypto} -eq 1 ]; then \ 132 dmsetup remove -f ${loop_dev} 133 ${LOSETUPBIN} -d ${old_loop_dev} 134 else \ 135 ${LOSETUPBIN} -d ${loop_dev} 136 fi 137 fi 138 if [ "x${tempfile}" != "x" -a -f "${tempfile}" ]; then \ 139 rm -f ${tempfile} 140 fi 141 if [ "x${keyfile}" != "x" -a -f "${keyfile}" ]; then \ 142 rm -f ${keyfile} 143 fi 144 echo "Fatal error." 145 exit 1 146} 147 148usage() { 149 echo "mkobb.sh -- Create OBB files for use on Android" 150 echo "" 151 echo " -d <directory> Use <directory> as input for OBB files" 152 echo " -k <key> Use <key> to encrypt OBB file" 153 echo " -K Prompt for key to encrypt OBB file" 154 echo " -o <filename> Write OBB file out to <filename>" 155 echo " -v Verbose mode" 156 echo " -h Help; this usage screen" 157} 158 159find_binaries 160check_prereqs 161 162use_crypto=0 163 164args=`getopt -o d:hk:Ko:v -- "$@"` 165eval set -- "$args" 166 167while true; do \ 168 case "$1" in 169 -d) directory=$2; shift 2;; 170 -h) usage; exit 1;; 171 -k) key=$2; use_crypto=1; shift 2;; 172 -K) prompt_key=1; use_crypto=1; shift;; 173 -v) verbose=1; shift;; 174 -o) filename=$2; shift 2;; 175 --) shift; break;; 176 *) echo "ERROR: Invalid argument in option parsing! Cannot recover. Ever."; exit 1;; 177 esac 178done 179 180if [ "${directory}x" = "x" -o ! -d "${directory}" ]; then \ 181 echo "ERROR: Must specify valid input directory" 182 echo "" 183 usage 184 exit 1; 185fi 186 187if [ "${filename}x" = "x" ]; then \ 188 echo "ERROR: Must specify filename" 189 echo "" 190 usage 191 exit 1; 192fi 193 194if [ ${use_crypto} -eq 1 -a "${key}x" = "x" -a 0${prompt_key} -eq 0 ]; then \ 195 echo "ERROR: Crypto desired, but no key supplied or requested to prompt for." 196 exit 1 197fi 198 199if [ 0${prompt_key} -eq 1 ]; then \ 200 read_key 201fi 202 203outdir=`dirname ${filename}` 204if [ ! -d "${outdir}" ]; then \ 205 echo "ERROR: Output directory does not exist: ${outdir}" 206 exit 1 207fi 208 209# Make sure we clean up any stuff we create from here on during error conditions 210trap onexit ERR 211 212tempfile=$(tempfile -d ${outdir}) || ( echo "ERROR: couldn't create temporary file in ${outdir}"; exit 1 ) 213 214block_count=`du -s --apparent-size --block-size=512 ${directory} | awk '{ print $1; }'` 215if [ $? -ne 0 ]; then \ 216 echo "ERROR: Couldn't read size of input directory ${directory}" 217 exit 1 218fi 219 220echo "Creating temporary file..." 221${DDBIN} if=/dev/zero of=${tempfile} bs=${BLOCK_SIZE} count=$((${block_count} + ${SLOP})) > /dev/null 2>&1 222if [ $? -ne 0 ]; then \ 223 echo "ERROR: creating temporary file: $?" 224fi 225 226loop_dev=$(${LOSETUPBIN} -f) || ( echo "ERROR: losetup wouldn't tell us the next unused device"; exit 1 ) 227 228${LOSETUPBIN} ${loop_dev} ${tempfile} || ( echo "ERROR: couldn't create loopback device"; exit 1 ) 229 230if [ ${use_crypto} -eq 1 ]; then \ 231 eval `${PBKDF2GEN} ${key}` 232 unique_dm_name=`basename ${tempfile}` 233 echo "0 `blockdev --getsize ${loop_dev}` crypt ${CRYPTO} ${key} 0 ${loop_dev} 0" | dmsetup create ${unique_dm_name} 234 old_loop_dev=${loop_dev} 235 loop_dev=/dev/mapper/${unique_dm_name} 236fi 237 238# 239# Create the filesystem 240# 241echo "" 242${MKFSBIN} -I ${loop_dev} 243echo "" 244 245# 246# Make the temporary mount point and mount it 247# 248temp_mount="${MOUNTDIR}/${RANDOM}" 249mkdir ${temp_mount} 250${MOUNTBIN} -t ${FS} -o loop ${loop_dev} ${temp_mount} 251 252# 253# rsync the files! 254# 255echo "Copying files:" 256${RSYNCBIN} -av --no-owner --no-group ${directory}/ ${temp_mount}/ 257echo "" 258 259echo "Successfully created \`${filename}'" 260 261if [ ${use_crypto} -eq 1 ]; then \ 262 echo "salt for use with obbtool is:" 263 echo "${salt}" 264fi 265 266# 267# Undo all the temporaries 268# 269umount ${temp_mount} 270rmdir ${temp_mount} 271if [ ${use_crypto} -eq 1 ]; then \ 272 dmsetup remove -f ${loop_dev} 273 ${LOSETUPBIN} -d ${old_loop_dev} 274else \ 275 ${LOSETUPBIN} -d ${loop_dev} 276fi 277mv ${tempfile} ${filename} 278 279trap - ERR 280 281exit 0 282