Skip to content

Instantly share code, notes, and snippets.

@ia
Created August 26, 2017 00:20
Show Gist options
  • Save ia/5324cde69779dd6efabd4422268204cd to your computer and use it in GitHub Desktop.
Save ia/5324cde69779dd6efabd4422268204cd to your computer and use it in GitHub Desktop.
#!/bin/sh
#
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# This attempts to guide linux users through the process of putting a recovery
# image onto a removeable USB drive.
#
# We may not need root privileges if we have the right permissions.
#
set -eu
##############################################################################
# Configuration goes here
# Where should we do our work? Use 'WORKDIR=' to make a temporary directory,
# but using a persistent location may let us resume interrupted downloads or
# run again without needing to download a second time.
WORKDIR=${WORKDIR:-/tmp/tmp.crosrec}
# Where do we look for the config file? We can override this for debugging by
# specifying "--config URL" on the command line, but curl and wget may handle
# file URLs differently.
CONFIGURL="${2:-https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.conf?source=linux_recovery.sh}"
# Device to put this stuff on, perhaps the user knows best?
DEVICE="${DEVICE:-}"
# What version is this script? It must match the 'recovery_tool_version=' value
# in the config file that we'll download.
MYVERSION='0.9.2'
##############################################################################
# Some temporary filenames
debug='debug.log'
tmpfile='tmp.txt'
config='config.txt'
version='version.txt'
##############################################################################
# Various warning messages
DEBUG() {
echo "DEBUG: $@" >>"$debug"
}
prompt() {
# builtin echo may not grok '-n'. We should always have /bin/echo, right?
/bin/echo -n "$@"
}
warn() {
echo "$@" 1>&2
}
quit() {
warn "quitting..."
exit 1
}
fatal() {
warn "ERROR: $@"
exit 1
}
ufatal() {
warn "
ERROR: $@
You may need to run this program as a different user. If that doesn't help, try
using a different computer, or ask a knowledgeable friend for help.
"
exit 1
}
gfatal() {
warn "
ERROR: $@
You may need to run this program as a different user. If that doesn't help, it
may be a networking problem or a problem with the images provided by Google.
You might want to check to see if there is a newer version of this tool
available, or if someone else has already reported a problem.
If all else fails, you could try using a different computer, or ask a
knowledgeable friend for help.
"
exit 1
}
##############################################################################
# Identify the external utilities that we MUST have available.
#
# I'd like to keep the set of external *NIX commands to an absolute minimum,
# but I have to balance that against producing mysterious errors because the
# shell can't always do everything. Let's make sure that these utilities are
# all in our $PATH, or die with an error.
#
# This also sets the following global variables to select alternative utilities
# when there is more than one equivalent tool available:
#
# FETCH = name of utility used to download files from the web
# CHECK = command to invoke to generate checksums on a file
# CHECKTYPE = type of checksum generated
# DISKUTIL = set if we have 'diskutil' (for Macs)
#
require_utils() {
local extern
local errors
local tool
local tmp
extern='awk cat cut dd grep ls mkdir mount readlink sed sync umount unzip wc'
if [ -z "$WORKDIR" ]; then
extern="$extern mktemp"
fi
errors=
for tool in $extern ; do
if ! type "$tool" >/dev/null 2>&1 ; then
warn "ERROR: need \"$tool\""
errors=yes
fi
done
# We also need to a way to fetch files from teh internets. Note that the args
# are different depending on which utility we find. We'll use two variants,
# one to fetch fresh every time and one to try again from where we left off.
FETCH=
if [ -z "$FETCH" ] && tmp=$(type curl 2>/dev/null) ; then
FETCH=curl
fi
if [ -z "$FETCH" ] && tmp=$(type wget 2>/dev/null) ; then
FETCH=wget
fi
if [ -z "$FETCH" ]; then
warn "ERROR: need \"curl\" or \"wget\""
errors=yes
fi
# Once we've fetched a file we need to compute its checksum. There are
# multiple possiblities here too.
CHECK=
if [ -z "$CHECK" ] && tmp=$(type md5sum 2>/dev/null) ; then
CHECK="md5sum"
CHECKTYPE="md5"
fi
if [ -z "$CHECK" ] && tmp=$(type sha1sum 2>/dev/null) ; then
CHECK="sha1sum"
CHECKTYPE="sha1"
fi
if [ -z "$CHECK" ] && tmp=$(type openssl 2>/dev/null) ; then
CHECK="openssl"
CHECKTYPE="md5"
fi
if [ -z "$CHECK" ]; then
warn "ERROR: need \"md5sum\" or \"sha1sum\" or \"openssl\""
errors=yes
fi
# This utility is on Macs, so use it if we find it.
DISKUTIL=
if type diskutil >/dev/null 2>&1; then
DISKUTIL=diskutil
fi
if [ -n "$errors" ]; then
ufatal "Some required utilities are missing."
fi
}
# This retrieves a URL and stores it locally. It uses the global variable
# 'FETCH' to determine the utility (and args) to invoke.
# Args: URL FILENAME [RESUME]
fetch_url() {
local url
local filename
local resume
local err
url="$1"
filename="$2"
resume="${3:-}"
DEBUG "FETCH=($FETCH) url=($url) filename=($filename) resume=($resume)"
if [ "$FETCH" = "curl" ]; then
if [ -z "$resume" ]; then
# quietly fetch a new copy each time
rm -f "$filename"
curl -L -f -s -S -o "$filename" "$url"
else
# continue where we left off, if possible
curl -L -f -C - -o "$filename" "$url"
# If you give curl the '-C -' option but the file you want is already
# complete and the server doesn't report the total size correctly, it
# will report an error instead of just doing nothing. We'll try to work
# around that.
err=$?
if [ "$err" = "18" ]; then
warn "Ignoring spurious complaint"
true
fi
fi
elif [ "$FETCH" = "wget" ]; then
if [ -z "$resume" ]; then
# quietly fetch a new copy each time
rm -f "$filename"
wget -nv -q -O "$filename" "$url"
else
# continue where we left off, if possible
wget -c -O "$filename" "$url"
fi
fi
}
# This returns a checksum on a file. It uses the global variable 'CHECK' to
# determine the utility (and args) to invoke.
# Args: FILENAME
compute_checksum() {
local filename
filename="$1"
DEBUG "CHECK=($CHECK) CHECKTYPE=($CHECKTYPE)"
if [ "$CHECK" = "openssl" ]; then
openssl md5 < "$filename"
else
$CHECK "$zipfile" | cut -d' ' -f1
fi
}
##############################################################################
# Helper functions to handle the config file and image zipfile.
# Convert bytes to MB, rounding up to determine storage needed to hold bytes.
roundup() {
local num=$1
local div=$(( 1024 * 1024 ))
local rem=$(( $num % $div ))
if [ $rem -ne 0 ]; then
num=$(($num + $div - $rem))
fi
echo $(( $num / $div ))
}
# Die unless the filesystem containing the current directory has enough free
# space. The argument is the number of MB required.
verify_tmp_space() {
local need
local got
need="$1"
# The output of "df -m ." could take two forms:
#
# Filesystem 1M-blocks Used Available Use% Mounted on
# /some/really/long/path/to/some/where
# 37546 11118 24521 32% /
#
# Filesystem 1048576-blocks Used Available Capacity Mounted on
# /some/short/path 37546 11118 24521 32% /
#
got=$(df -m . | awk '/^\/[^ ]+ +[0-9]/ {print $4} /^ +[0-9]/ {print $3}')
if [ "$need" -gt "$got" ]; then
fatal " There is not enough free space in ${WORKDIR}" \
"(it has ${got}MB, we need ${need}MB).
Please free up some space on that filesystem, or specify a temporary directory
on the commandline like so:
WORKDIR=/path/to/some/dir $0
"
fi
}
# Each paragraph in the config file should describe a new image. Let's make
# sure it follows all the rules. This scans the config file and returns success
# if it looks valid. As a side-effect, it lists the line numbers of the start
# and end of each stanza in the global variables 'start_lines' and 'end_lines'
# and saves the total number of images in the global variable 'num_images'.
good_config() {
local line
local key
local val
local name
local file
local zipfilesize
local filesize
local url
local md5
local sha1
local skipping
local errors
local count
local line_num
name=
file=
zipfilesize=
filesize=
url=
md5=
sha1=
skipping=yes
errors=
count=0
line_num=0
# global
start_lines=
end_lines=
while read line; do
line_num=$(( line_num + 1 ))
# We might have some empty lines before the first stanza. Skip them.
if [ -n "$skipping" ] && [ -z "$line" ]; then
continue
fi
# Got something...
if [ -n "$line" ]; then
key=${line%=*}
val=${line#*=}
if [ -z "$key" ] || [ -z "$val" ] || [ "$key=$val" != "$line" ]; then
DEBUG "ignoring $line"
continue
fi
# right, looks good
if [ -n "$skipping" ]; then
skipping=
start_lines="$start_lines $line_num"
fi
case $key in
name)
if [ -n "$name" ]; then
DEBUG "duplicate $key"
errors=yes
fi
name="$val"
;;
file)
if [ -n "$file" ]; then
DEBUG "duplicate $key"
errors=yes
fi
file="$val"
;;
zipfilesize)
if [ -n "$zipfilesize" ]; then
DEBUG "duplicate $key"
errors=yes
fi
zipfilesize="$val"
;;
filesize)
if [ -n "$filesize" ]; then
DEBUG "duplicate $key"
errors=yes
fi
filesize="$val"
;;
url)
url="$val"
;;
md5)
md5="$val"
;;
sha1)
sha1="$val"
;;
esac
else
# Between paragraphs. Time to check what we've found so far.
end_lines="$end_lines $line_num"
count=$(( count + 1))
if [ -z "$name" ]; then
DEBUG "image $count is missing name"
errors=yes
fi
if [ -z "$file" ]; then
DEBUG "image $count is missing file"
errors=yes
fi
if [ -z "$zipfilesize" ]; then
DEBUG "image $count is missing zipfilesize"
errors=yes
fi
if [ -z "$filesize" ]; then
DEBUG "image $count is missing filesize"
errors=yes
fi
if [ -z "$url" ]; then
DEBUG "image $count is missing url"
errors=yes
fi
if [ "$CHECKTYPE" = "md5" ] && [ -z "$md5" ]; then
DEBUG "image $count is missing required md5"
errors=yes
fi
if [ "$CHECKTYPE" = "sha1" ] && [ -z "$sha1" ]; then
DEBUG "image $count is missing required sha1"
errors=yes
fi
# Prepare for next stanza
name=
file=
zipfilesize=
filesize=
url=
md5=
sha1=
skipping=yes
fi
done < "$config"
DEBUG "$count images found"
num_images="$count"
DEBUG "start_lines=($start_lines)"
DEBUG "end_lines=($end_lines)"
# return error status
[ "$count" != "0" ] && [ -z "$errors" ]
}
# Make the user pick an image to download. On success, it sets the global
# variable 'user_choice' to the selected image number.
choose_image() {
local show
local count
local line
local num
local hwidprefix
local showheader
local headershown
local showhwid
local showregexp
local regexpshown
local curname
local curchannel
local curregexp
local space=" "
local caret="^"
show=yes
while true; do
if [ -n "$show" ]; then
echo
echo "If you know the Model string displayed at the recovery screen,"
prompt "type some or all of it; otherwise just press Enter: "
read hwidprefix
hwidprefix=`echo $hwidprefix | tr [a-z] [A-Z] `
echo
echo "This may take a few minutes to print the full list..."
echo
if [ "$num_images" -gt 1 ]; then
echo "There are up to $num_images recovery images to choose from:"
else
echo "There is $num_images recovery image to choose from:"
fi
echo
count=0
echo "0 - <quit>"
# NOTE: making assumptions about the order of lines in each stanza!
while read line; do
# Got something...
if [ -n "$line" ]; then
# Extract key/value pair
key=${line%=*}
val=${line#*=}
if [ -z "$key" ] || [ -z "$val" ] || \
[ "$key=$val" != "$line" ]; then
DEBUG "ignoring $line"
continue
fi
showhwid=
showregexp=
case $key in
name)
count=$(( count + 1 ))
headershown=
curname=${val}
curregexp=
regexpshown=
;;
channel)
curchannel=${val}
;;
hwidmatch)
curregexp=${val}
if [ -n "$hwidprefix" ]; then
# Prefix specified
if echo "$hwidprefix" | grep -q "$curregexp"; then
# Prefix matches regex.
# e.g.
# prefix: PEPPY A1C
# regex: ^PEPPY .*
showregexp=true
elif echo "$hwidprefix$space" | grep -q "$curregexp"; then
# Prefix with space added matches regex.
# e.g.
# prefix: PEPPY
# regex: ^PEPPY .*
showregexp=true
elif echo $curregexp | grep -q "^${hwidprefix}.*"; then
# Regex starts with the prefix.
# e.g.
# prefix: SAMS
# regex: SAMS ALEX BETA-DOGFOOD 9650|SAMS ALEX BETA-US 8738|...
showregexp=true
elif echo $curregexp | grep -q "^${caret}${hwidprefix}.*"; then
# Regex starts with the prefix preceeded by a carret.
# e.g.
# prefix: MIGHTY
# regex: ^MIGHTY [A-Z0-9]{3}-[A-Z0-9]{3}-[A-Z0-9]{3}-E[A-Z0-9]{2}-[A-Z0-9]{3}
showregexp=true
fi
else
# If there is no prefix specified, show the hwid match.
showregexp=true
fi
;;
esac
# Show header at most once per image
if [ -z "$headershown" ]; then
if [ -n "$showregexp" ] || [ -n "$showhwid" ]; then
echo "$count - $curname"
echo " channel: $curchannel"
headershown=true
fi
fi
if [ -z "$regexpshown" ] && [ -n "$showregexp" ] &&
[ -n "$curregexp" ]; then
echo " pattern: $curregexp"
regexpshown=true
elif [ -n "$showhwid" ]; then
echo " model: $curhwid"
fi
fi
done < "$config"
echo
show=
fi
prompt "Please select a recovery image to download: "
read num
if [ -z "$num" ] || [ "$num" = "?" ]; then
show=yes
elif echo "$num" | grep -q '[^0-9]'; then
echo "Sorry, I didn't understand that."
else
if [ "$num" -lt "0" ] || [ "$num" -gt "$num_images" ]; then
echo "That's not one of the choices."
elif [ "$num" -eq 0 ]; then
quit
else
break;
fi
fi
done
echo
# global
user_choice="$num"
}
# Fetch and verify the user's chosen image. On success, it sets the global
# variable 'image_file' to indicate the local name of the unpacked binary that
# should be written to the USB drive. It also sets the global variable
# 'disk_needed' to the minimum capacity of the USB drive required (in MB).
fetch_image() {
local start
local end
local line
local key
local val
local file
local zipfilesize
local filesize
local url
local md5
local sha1
local line_num
local zipfile
local err
local sum
file=
zipfilesize=
filesize=
url=
md5=
sha1=
line_num="0"
# Convert image number to line numbers within config file.
start=$(echo $start_lines | cut -d' ' -f$1)
end=$(echo $end_lines | cut -d' ' -f$1)
while read line; do
# Skip to the start of the desired stanza
line_num=$(( line_num + 1 ))
if [ "$line_num" -lt "$start" ] || [ "$line_num" -ge "$end" ]; then
continue;
fi
# Process the stanza.
if [ -n "$line" ]; then
key=${line%=*}
val=${line#*=}
if [ -z "$key" ] || [ -z "$val" ] || [ "$key=$val" != "$line" ]; then
DEBUG "ignoring $line"
continue
fi
case $key in
# The descriptive stuff we'll just save for later.
file)
file="$val"
;;
zipfilesize)
zipfilesize="$val"
;;
filesize)
filesize="$val"
;;
md5)
md5="$val"
;;
sha1)
sha1="$val"
;;
url)
# Make sure we have enough temp space available. Die if we don't.
verify_tmp_space $(roundup $(( $zipfilesize + $filesize )))
# Try to download each url until one works.
if [ -n "$url" ]; then
# We've already got one (it's very nice).
continue;
fi
warn "Downloading image zipfile from $val"
warn ""
zipfile=${val##*/}
if fetch_url "$val" "$zipfile" "resumeok"; then
# Got it.
url="$val"
fi
;;
esac
fi
done < "$config"
if [ -z "$url" ]; then
DEBUG "couldn't fetch zipfile"
return 1
fi
# Verify the zipfile
if ! ls -l "$zipfile" | grep -q "$zipfilesize"; then
DEBUG "zipfilesize is wrong"
return 1
fi
sum=$(compute_checksum "$zipfile")
DEBUG "checksum is $sum"
if [ "$CHECKTYPE" = "md5" ] && [ "$sum" != "$md5" ]; then
DEBUG "wrong $CHECK"
return 1
elif [ "$CHECKTYPE" = "sha1" ] && [ "$sum" != "$sha1" ]; then
DEBUG "wrong $CHECK"
return 1
fi
# Unpack the file
warn "Unpacking the zipfile"
rm -f "$file"
if ! unzip "$zipfile" "$file"; then
DEBUG "Can't unpack the zipfile"
return 1
fi
if ! ls -l "$file" | grep -q "$filesize"; then
DEBUG "unpacked filesize is wrong"
return 1
fi
# global
image_file="$file"
disk_needed=$(roundup "$filesize")
}
##############################################################################
# Helper functions to manage USB drives.
# Return a list of base device names ("sda sdb ...") for all USB drives
get_devlist() {
local dev
local t
local r
# Are we on a mac?
if [ -n "$DISKUTIL" ]; then
for dev in $(diskutil list | grep '^/dev'); do
r=$(diskutil info $dev | grep 'Ejectable\: *Yes') || true
t=$(diskutil info $dev | grep 'Protocol\: *USB') || true
if [ "$r" != "" ]; then
if [ "$t" != "" ]; then
echo "$dev" | sed 's,/dev/,,'
fi
fi
done
else
# No, linux, I hope
for dev in $(cat /proc/partitions); do
[ -r "/sys/block/$dev/device/type" ] &&
t=$(cat "/sys/block/$dev/device/type") &&
[ "$t" = "0" ] &&
r=$(cat "/sys/block/$dev/removable") &&
[ "$r" = "1" ] &&
readlink -f "/sys/block/$dev" | grep -q -i usb &&
echo "$dev" || true
done
fi
}
# Return the raw size in MB of each provided base device name ("sda sdb ...")
get_devsize() {
local dev
local bytes
local sectors
# Are we on a mac?
if [ -n "$DISKUTIL" ]; then
for dev in $1; do
bytes=$(diskutil info $dev | \
awk '/\([0-9]+ Bytes\)/' | sed -E 's/.*\(([0-9]+) Bytes\).*/\1/')
echo $(( $bytes / 1024 / 1024))
done
else
for dev in $1; do
sectors=$(cat "/sys/block/$dev/size")
echo $(( $sectors * 512 / 1024 / 1024 ))
done
fi
}
# Return descriptions for each provided base device name ("sda sdb ...")
get_devinfo() {
local dev
local v
local m
local s
local ss
# Are we on a mac?
if [ -n "$DISKUTIL" ]; then
for dev in $1; do
m=$(diskutil info $dev | grep 'Device \/ Media Name\:' | \
sed 's/^[^:]*: *//') || true
s=$(diskutil info $dev | grep 'Total Size\:' | \
sed 's/^[^:]*: *\([^(]*\).*/\1/') || true
echo "/dev/$dev $s $m"
done
else
# No, linux, hopefully
for dev in $1; do
v=$(cat "/sys/block/$dev/device/vendor") &&
m=$(cat "/sys/block/$dev/device/model") &&
s=$(cat "/sys/block/$dev/size") && ss=$(( $s * 512 / 1000000 )) &&
echo "/dev/$dev ${ss}MB $v $m"
done
fi
}
# Enumerate and descript the specified base device names ("sda sdb ...")
get_choices() {
local dev
local desc
local count
count=1
echo "0 - <quit>"
for dev in $1; do
desc=$(get_devinfo "$dev")
echo ""
echo "$count - Use $desc"
count=$(( count + 1 ))
done
}
# Make the user pick a USB drive to write to. On success, it sets the global
# variable 'user_choice' to the selected device name ("sda", "sdb", etc.)
choose_drive() {
local show
local devlist
local choices
local num_drives
local msg
local num
show=yes
while true; do
if [ -n "$show" ]; then
devlist=$(get_devlist)
choices=$(get_choices "$devlist")
if [ -z "$devlist" ]; then
num_drives="0"
msg="I can't seem to find a valid USB drive."
else
num_drives=$(echo "$devlist" | wc -l)
if [ "$num_drives" != "1" ]; then
msg="I found $num_drives USB drives."
else
msg="I found $num_drives USB drive."
fi
fi
echo "
$msg We need one with at least ${disk_needed}MB capacity.
$choices
"
show=
fi
prompt "Tell me what to do (or just press Enter to scan again): "
read num
if [ -z "$num" ] || [ "$num" = "?" ]; then
show=yes
elif echo "$num" | grep -q '[^0-9]'; then
echo "Sorry, I didn't understand that."
else
if [ "$num" -lt "0" ] || [ "$num" -gt "$num_drives" ]; then
echo "That's not one of the choices."
elif [ "$num" -eq 0 ]; then
quit
else
break;
fi
fi
done
# global
user_choice=$(echo $devlist | cut -d' ' -f$num)
}
# Unmount a partition
unmount_partition() {
if [ -n "$DISKUTIL" ]; then
diskutil unmountDisk "$1" || ufatal "Unable to unmount $1."
else
umount "$1" || ufatal "Unable to unmount $1."
fi
}
##############################################################################
# Okay, do something...
# Warn about usage
if [ -n "${1:-}" ] && [ "$1" != "--config" ]; then
echo "This program takes no arguments. Just run it."
# That's not really true. For debugging you can specify "--config URL".
exit 1
fi
# Make sure we have the tools we need
require_utils
# Tell user to use the new Chromebook Recovery Utility
warn ""
warn "======================================================================"
warn "This tool is in maintenance mode."
warn "Try the new Chromebook Recovery Utility on Chrome OS, Windows, or Mac."
warn "For more information, visit http://www.google.com/chromeos/recovery."
warn "======================================================================"
warn ""
# Need a place to work. We prefer a fixed location so we can try to resume any
# interrupted downloads.
if [ -n "$WORKDIR" ]; then
if [ ! -d "$WORKDIR" ] && ! mkdir "$WORKDIR" ; then
warn "Using temporary directory"
WORKDIR=
fi
fi
if [ -z "$WORKDIR" ]; then
WORKDIR=$(mktemp -d)
# Clean up temporary directory afterwards
trap "cd; rm -rf ${WORKDIR}" EXIT
fi
cd "$WORKDIR"
warn "Working in $WORKDIR/"
rm -f "$debug"
# Download the config file to see what choices we have.
DISPLAYED_CONFIGURL=`echo $CONFIGURL | sed s/\?.*//`
warn "Downloading config file from $DISPLAYED_CONFIGURL"
fetch_url "$CONFIGURL" "$tmpfile" || \
gfatal "Unable to download the config file"
# Separate the version info from the images
grep '^recovery_tool' "$tmpfile" > "$version"
grep -v '^#' "$tmpfile" | grep -v '^recovery_tool' > "$config"
# Add one empty line to the config file to terminate the last stanza
echo >> "$config"
# Make sure that the config file version matches this script version.
tmp=$(grep '^recovery_tool_linux_version=' "$version") || \
tmp=$(grep '^recovery_tool_version=' "$version") || \
gfatal "The config file doesn't contain a version string."
filevers=${tmp#*=}
if [ "$filevers" != "$MYVERSION" ]; then
tmp=$(grep '^recovery_tool_update=' "$version");
msg=${tmp#*=}
warn "This tool is version $MYVERSION." \
"The config file is for version $filevers."
fatal ${msg:-Please download a matching version of the tool and try again.}
fi
# Check the config file to be sure it's valid. As a side-effect, this sets the
# global variable 'num_images' with the number of image stanzas read, but
# that's independent of whether the config is valid.
good_config || gfatal "The config file isn't valid."
# Make the user pick an image to download, or exit.
choose_image
# Download the user's choice
fetch_image "$user_choice" || \
gfatal "Unable to download a valid recovery image."
if [ -n "$DEVICE" ]; then
user_choice="${DEVICE#/dev/}"
dev_desc="${DEVICE}"
else
# Make the user pick a USB drive, or exit.
choose_drive
# Be sure
dev_desc=$(get_devinfo "$user_choice")
fi
# Start asking for confirmation
dev_size=$(get_devsize "$user_choice")
if [ "$dev_size" -lt "$disk_needed" ]; then
echo "
WARNING: This drive seems too small (${dev_size}MB)." \
"The recovery image is ${disk_needed}MB."
fi
echo "
Is this the device you want to put the recovery image on?
$dev_desc
"
prompt "You must enter 'YES' (all uppercase) to continue: "
read tmp
if [ "$tmp" != "YES" ]; then
quit
fi
# Be very sure
echo "
I'm really going to erase this device. This will permanently ERASE
whatever you may have on that drive. You won't be able to undo it.
$dev_desc
"
prompt "If you're sure that's correct, enter 'DoIt' now (case is important): "
read tmp
if [ "$tmp" != "DoIt" ]; then
quit
fi
echo "
Installing the recovery image
"
# Unmount anything on that device.
echo "unmounting..."
for tmp in $(mount | grep ^"/dev/${user_choice}" | cut -d' ' -f1); do
unmount_partition "$tmp"
done
# Write it.
echo "copying... (this may take several minutes)"
# Many BSD variants provide both normal /dev/FOO and raw /dev/rFOO devices,
# with the raw path being much faster. If that device exists, we'll use it.
if [ -e /dev/r${user_choice} ]; then
user_choice="r${user_choice}"
fi
dd bs=4194304 of=/dev/${user_choice} if="$image_file" conv=sync ||
ufatal "Unable to write the image."
sync
echo "
Done. Remove the USB drive and insert it in your Chrome notebook.
"
prompt "Shall I remove the temporary files now? [y/n] "
read tmp
case $tmp in
[Yy]*)
cd
\rm -rf ${WORKDIR}
;;
esac
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment