blob: 725250d25385d08b4fc586d17e2c5cea448526f0 [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -08001#!/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