Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 1 | #!/bin/bash |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 2 | #===- lib/asan/scripts/asan_device_setup -----------------------------------===# |
| 3 | # |
| 4 | # The LLVM Compiler Infrastructure |
| 5 | # |
| 6 | # This file is distributed under the University of Illinois Open Source |
| 7 | # License. See LICENSE.TXT for details. |
| 8 | # |
| 9 | # Prepare Android device to run ASan applications. |
| 10 | # |
| 11 | #===------------------------------------------------------------------------===# |
| 12 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 13 | set -e |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 14 | |
| 15 | HERE="$(cd "$(dirname "$0")" && pwd)" |
| 16 | |
| 17 | revert=no |
| 18 | extra_options= |
| 19 | device= |
| 20 | lib= |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 21 | use_su=0 |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 22 | |
| 23 | function usage { |
| 24 | echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]" |
| 25 | echo " --revert: Uninstall ASan from the device." |
| 26 | echo " --lib: Path to ASan runtime library." |
| 27 | echo " --extra-options: Extra ASAN_OPTIONS." |
| 28 | echo " --device: Install to the given device. Use 'adb devices' to find" |
| 29 | echo " device-id." |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 30 | echo " --use-su: Use 'su -c' prefix for every adb command instead of using" |
| 31 | echo " 'adb root' once." |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 32 | echo |
| 33 | exit 1 |
| 34 | } |
| 35 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 36 | function adb_push { |
| 37 | if [ $use_su -eq 0 ]; then |
| 38 | $ADB push "$1" "$2" |
| 39 | else |
| 40 | local FILENAME=$(basename $1) |
| 41 | $ADB push "$1" "/data/local/tmp/$FILENAME" |
| 42 | $ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null |
| 43 | $ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\"" |
| 44 | $ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\"" |
| 45 | fi |
| 46 | } |
| 47 | |
| 48 | function adb_remount { |
| 49 | if [ $use_su -eq 0 ]; then |
| 50 | $ADB remount |
| 51 | else |
| 52 | local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1` |
| 53 | if [ "$STORAGE" != "" ]; then |
| 54 | echo Remounting $STORAGE at /system |
| 55 | $ADB shell su -c "mount -o remount,rw $STORAGE /system" |
| 56 | else |
| 57 | echo Failed to get storage device name for "/system" mount point |
| 58 | fi |
| 59 | fi |
| 60 | } |
| 61 | |
| 62 | function adb_shell { |
| 63 | if [ $use_su -eq 0 ]; then |
| 64 | $ADB shell $@ |
| 65 | else |
| 66 | $ADB shell su -c "$*" |
| 67 | fi |
| 68 | } |
| 69 | |
| 70 | function adb_root { |
| 71 | if [ $use_su -eq 0 ]; then |
| 72 | $ADB root |
| 73 | fi |
| 74 | } |
| 75 | |
| 76 | function adb_wait_for_device { |
| 77 | $ADB wait-for-device |
| 78 | } |
| 79 | |
| 80 | function adb_pull { |
| 81 | if [ $use_su -eq 0 ]; then |
| 82 | $ADB pull "$1" "$2" |
| 83 | else |
| 84 | local FILENAME=$(basename $1) |
| 85 | $ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null |
| 86 | $ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" && |
| 87 | $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\"" |
| 88 | fi |
| 89 | } |
| 90 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 91 | function get_device_arch { # OUTVAR |
| 92 | local _outvar=$1 |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 93 | local _ABI=$(adb_shell getprop ro.product.cpu.abi) |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 94 | local _ARCH= |
| 95 | if [[ $_ABI == x86* ]]; then |
| 96 | _ARCH=i686 |
| 97 | elif [[ $_ABI == armeabi* ]]; then |
| 98 | _ARCH=arm |
| 99 | else |
| 100 | echo "Unrecognized device ABI: $_ABI" |
| 101 | exit 1 |
| 102 | fi |
| 103 | eval $_outvar=\$_ARCH |
| 104 | } |
| 105 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 106 | while [[ $# > 0 ]]; do |
| 107 | case $1 in |
| 108 | --revert) |
| 109 | revert=yes |
| 110 | ;; |
| 111 | --extra-options) |
| 112 | shift |
| 113 | if [[ $# == 0 ]]; then |
| 114 | echo "--extra-options requires an argument." |
| 115 | exit 1 |
| 116 | fi |
| 117 | extra_options="$1" |
| 118 | ;; |
| 119 | --lib) |
| 120 | shift |
| 121 | if [[ $# == 0 ]]; then |
| 122 | echo "--lib requires an argument." |
| 123 | exit 1 |
| 124 | fi |
| 125 | lib="$1" |
| 126 | ;; |
| 127 | --device) |
| 128 | shift |
| 129 | if [[ $# == 0 ]]; then |
| 130 | echo "--device requires an argument." |
| 131 | exit 1 |
| 132 | fi |
| 133 | device="$1" |
| 134 | ;; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 135 | --use-su) |
| 136 | use_su=1 |
| 137 | ;; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 138 | *) |
| 139 | usage |
| 140 | ;; |
| 141 | esac |
| 142 | shift |
| 143 | done |
| 144 | |
| 145 | ADB=${ADB:-adb} |
| 146 | if [[ x$device != x ]]; then |
| 147 | ADB="$ADB -s $device" |
| 148 | fi |
| 149 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 150 | if [ $use_su -eq 1 ]; then |
| 151 | # Test if 'su' is present on the device |
| 152 | SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'` |
| 153 | if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then |
| 154 | echo "ERROR: Cannot use 'su -c':" |
| 155 | echo "$ adb shell su -c \"echo foo\"" |
| 156 | echo $SU_TEST_OUT |
| 157 | echo "Check that 'su' binary is correctly installed on the device or omit" |
| 158 | echo " --use-su flag" |
| 159 | exit 1 |
| 160 | fi |
| 161 | fi |
| 162 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 163 | echo '>> Remounting /system rw' |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 164 | adb_wait_for_device |
| 165 | adb_root |
| 166 | adb_wait_for_device |
| 167 | adb_remount |
| 168 | adb_wait_for_device |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 169 | |
| 170 | get_device_arch ARCH |
| 171 | echo "Target architecture: $ARCH" |
| 172 | ASAN_RT="libclang_rt.asan-$ARCH-android.so" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 173 | |
| 174 | if [[ x$revert == xyes ]]; then |
| 175 | echo '>> Uninstalling ASan' |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 176 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 177 | if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 178 | echo '>> Pre-L device detected.' |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 179 | adb_shell mv /system/bin/app_process.real /system/bin/app_process |
| 180 | adb_shell rm /system/bin/asanwrapper |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 181 | else |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 182 | adb_shell rm /system/bin/app_process.wrap |
| 183 | adb_shell rm /system/bin/asanwrapper |
| 184 | adb_shell rm /system/bin/app_process |
| 185 | adb_shell ln -s /system/bin/app_process32 /system/bin/app_process |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 186 | fi |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 187 | |
| 188 | echo '>> Restarting shell' |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 189 | adb_shell stop |
| 190 | adb_shell start |
| 191 | |
| 192 | # Remove the library on the last step to give a chance to the 'su' binary to |
| 193 | # be executed without problem. |
| 194 | adb_shell rm /system/lib/$ASAN_RT |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 195 | |
| 196 | echo '>> Done' |
| 197 | exit 0 |
| 198 | fi |
| 199 | |
| 200 | if [[ -d "$lib" ]]; then |
| 201 | ASAN_RT_PATH="$lib" |
| 202 | elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then |
| 203 | ASAN_RT_PATH=$(dirname "$lib") |
| 204 | elif [[ -f "$HERE/$ASAN_RT" ]]; then |
| 205 | ASAN_RT_PATH="$HERE" |
| 206 | elif [[ $(basename "$HERE") == "bin" ]]; then |
| 207 | # We could be in the toolchain's base directory. |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 208 | # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux. |
| 209 | P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/linux/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1) |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 210 | if [[ -n "$P" ]]; then |
| 211 | ASAN_RT_PATH="$(dirname "$P")" |
| 212 | fi |
| 213 | fi |
| 214 | |
| 215 | if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 216 | echo ">> ASan runtime library not found" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 217 | exit 1 |
| 218 | fi |
| 219 | |
| 220 | TMPDIRBASE=$(mktemp -d) |
| 221 | TMPDIROLD="$TMPDIRBASE/old" |
| 222 | TMPDIR="$TMPDIRBASE/new" |
| 223 | mkdir "$TMPDIROLD" |
| 224 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 225 | RELEASE=$(adb_shell getprop ro.build.version.release) |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 226 | PRE_L=0 |
| 227 | if echo "$RELEASE" | grep '^4\.' >&/dev/null; then |
| 228 | PRE_L=1 |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 229 | fi |
| 230 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 231 | if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 232 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 233 | if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 234 | echo '>> Old-style ASan installation detected. Reverting.' |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 235 | adb_shell mv /system/bin/app_process.real /system/bin/app_process |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 236 | fi |
| 237 | |
| 238 | echo '>> Pre-L device detected. Setting up app_process symlink.' |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 239 | adb_shell mv /system/bin/app_process /system/bin/app_process32 |
| 240 | adb_shell ln -s /system/bin/app_process32 /system/bin/app_process |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 241 | fi |
| 242 | |
| 243 | echo '>> Copying files from the device' |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 244 | adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true |
| 245 | adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true |
| 246 | adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 247 | cp -r "$TMPDIROLD" "$TMPDIR" |
| 248 | |
| 249 | if [[ -f "$TMPDIR/app_process.wrap" ]]; then |
| 250 | echo ">> Previous installation detected" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 251 | else |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 252 | echo ">> New installation" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 253 | fi |
| 254 | |
| 255 | echo '>> Generating wrappers' |
| 256 | |
| 257 | cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/" |
| 258 | |
| 259 | # FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup, |
| 260 | # which may or may not be a real bug (probably not). |
| 261 | ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0 |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 262 | |
| 263 | # On Android-L not allowing user segv handler breaks some applications. |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 264 | if [[ PRE_L -eq 0 ]]; then |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 265 | ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" |
| 266 | fi |
| 267 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 268 | if [[ x$extra_options != x ]] ; then |
| 269 | ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" |
| 270 | fi |
| 271 | |
| 272 | # Zygote wrapper. |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 273 | cat <<EOF >"$TMPDIR/app_process.wrap" |
| 274 | #!/system/bin/sh-from-zygote |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 275 | ASAN_OPTIONS=$ASAN_OPTIONS \\ |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 276 | LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\ |
| 277 | exec /system/bin/app_process32 \$@ |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 278 | |
| 279 | EOF |
| 280 | |
| 281 | # General command-line tool wrapper (use for anything that's not started as |
| 282 | # zygote). |
| 283 | cat <<EOF >"$TMPDIR/asanwrapper" |
| 284 | #!/system/bin/sh |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 285 | LD_PRELOAD=$ASAN_RT \\ |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 286 | exec \$@ |
| 287 | |
| 288 | EOF |
| 289 | |
| 290 | if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then |
| 291 | echo '>> Pushing files to the device' |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 292 | adb_push "$TMPDIR/$ASAN_RT" /system/lib/ |
| 293 | adb_push "$TMPDIR/app_process.wrap" /system/bin |
| 294 | adb_push "$TMPDIR/asanwrapper" /system/bin |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 295 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 296 | adb_shell rm /system/bin/app_process |
| 297 | adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 298 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 299 | adb_shell chown root.shell \ |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 300 | /system/lib/"$ASAN_RT" \ |
| 301 | /system/bin/app_process.wrap \ |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 302 | /system/bin/asanwrapper |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 303 | adb_shell chmod 644 \ |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 304 | /system/lib/"$ASAN_RT" |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 305 | adb_shell chmod 755 \ |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 306 | /system/bin/app_process.wrap \ |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 307 | /system/bin/asanwrapper |
| 308 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 309 | # Make SELinux happy by keeping app_process wrapper and the shell |
| 310 | # it runs on in zygote domain. |
| 311 | ENFORCING=0 |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 312 | if adb_shell getenforce | grep Enforcing >/dev/null; then |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 313 | # Sometimes shell is not allowed to change file contexts. |
| 314 | # Temporarily switch to permissive. |
| 315 | ENFORCING=1 |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 316 | adb_shell setenforce 0 |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 317 | fi |
| 318 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 319 | adb_shell cp /system/bin/sh /system/bin/sh-from-zygote |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 320 | |
| 321 | if [[ PRE_L -eq 1 ]]; then |
| 322 | CTX=u:object_r:system_file:s0 |
| 323 | else |
| 324 | CTX=u:object_r:zygote_exec:s0 |
| 325 | fi |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 326 | adb_shell chcon $CTX \ |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 327 | /system/bin/sh-from-zygote \ |
| 328 | /system/bin/app_process.wrap \ |
| 329 | /system/bin/app_process32 |
| 330 | |
| 331 | if [ $ENFORCING == 1 ]; then |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 332 | adb_shell setenforce 1 |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 333 | fi |
| 334 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 335 | echo '>> Restarting shell (asynchronous)' |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 336 | adb_shell stop |
| 337 | adb_shell start |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 338 | |
| 339 | echo '>> Please wait until the device restarts' |
| 340 | else |
| 341 | echo '>> Device is up to date' |
| 342 | fi |
| 343 | |
| 344 | rm -r "$TMPDIRBASE" |