Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 503 lines (430 sloc) 14.3 KB
#!/sbin/sh
set -e
if [ ! -e "$1" ]; then
echo "Command file doesn't exist: $1"
exit 1
fi
mv $1 $1.applying
COMMAND_FILE=$1.applying
REMOVE_LIST="$COMMAND_FILE"
# Used as a security check to see if we would change the password
DATA_FORMAT=0
# System Mountpoint
SYSTEM_MOUNTPOINT=/cache/system
echo "Starting image upgrader: $(date)"
# Functions
verify_signature() {
# $1 => validation keyring name
# $2 => path to validate
if [ -e /etc/system-image/skip-gpg-verification ]; then
return 0
fi
if [ ! -e $2 ]; then
echo "File doesn't exist: $2"
return 1
fi
# Check against the blacklist
if [ -e /tmp/system-image/blacklist/pubring.gpg ]; then
export GNUPGHOME=/tmp/system-image/blacklist/
if gpg --ignore-time-conflict --verify $2 >/dev/null 2>&1; then
echo "File signed by a blacklisted key: $2"
return 1
fi
fi
# Check against the keyring
export GNUPGHOME=/tmp/system-image/$1/
if [ ! -e "$GNUPGHOME" ]; then
echo "Keyring doesn't exist: $1"
return 1
fi
if gpg --ignore-time-conflict --verify $2 >/dev/null 2>&1; then
return 0
fi
return 1
}
install_keyring() {
# $1 => full path to tarball
# $2 => full path to signature
# Some basic checks
if [ ! -e "$1" ] || [ ! -e "$2" ]; then
echo "Missing keyring files: $1 => $2"
return 1
fi
# Unpacking
TMPDIR="$(mktemp -d /tmp.XXXXXX)"
cd $TMPDIR
cat $1 | unxz | tar xf -
if [ ! -e keyring.json ] || [ ! -e keyring.gpg ]; then
rm -Rf $TMPDIR
echo "Invalid keyring: $1"
return 1
fi
# Extract the expiry
keyring_expiry=$(grep "^ \"expiry\": " keyring.json | cut -d: -f2 | sed -e "s/[ \",]//g")
if [ -n "$keyring_expiry" ] && [ "$keyring_expiry" -lt "$(date +%s)" ]; then
rm -Rf $TMPDIR
echo "Keyring expired: $1"
return 1
fi
# Extract the keyring type
keyring_type=$(grep "^ \"type\": " keyring.json | cut -d: -f2 | sed -e "s/[, \"]//g")
if [ -z "$keyring_type" ]; then
rm -Rf $TMPDIR
echo "Missing keyring type: $1"
return 1
fi
if [ -e /tmp/system-image/$keyring_type ]; then
rm -Rf $TMPDIR
echo "Keyring already loaded: $1"
return 1
fi
signer="unknown"
case "$keyring_type" in
archive-master)
signer=""
;;
image-master)
signer="archive-master"
;;
image-signing|blacklist)
signer="image-master"
;;
device-signing)
signer="image-signing"
;;
esac
if [ -n "$signer" ] && ! verify_signature $signer $2; then
rm -Rf $TMPDIR
echo "Invalid signature: $1"
return 1
fi
mkdir /tmp/system-image/$keyring_type
chmod 700 /tmp/system-image/$keyring_type
mv $TMPDIR/keyring.gpg /tmp/system-image/$keyring_type/pubring.gpg
chmod 600 /tmp/system-image/$keyring_type/pubring.gpg
chown 0:0 /tmp/system-image/$keyring_type/pubring.gpg
rm -Rf $TMPDIR
return 0
}
property_write() {
prop="$1"
prop_value="$2"
prop_dir="/data/android-data/property"
# everything is wiped after a format, let's get a skeleton going
mkdir -p "$prop_dir"
chown 0:0 "$prop_dir"
chmod 700 "$prop_dir"
echo -n "$prop_value" > "$prop_dir/$prop"
# properties won't be read if they aren't ro root
chown 0:0 "$prop_dir/$prop"
chmod 600 "$prop_dir/$prop"
}
set_password() {
if [ "$DATA_FORMAT" -eq 0 ]; then
return 1
fi
user="phablet"
password="$1"
if [ -z "$password" ]; then
return 1
fi
path=/bin:/usr/bin:/sbin:/usr/sbin
PATH=$path chroot "$SYSTEM_MOUNTPOINT" /bin/sh -c "echo -n "$user:$password" | chpasswd"
return 0
}
unset_password() {
if [ "$DATA_FORMAT" -eq 0 ]; then
return 1
fi
# Needs implementation
}
usb_enable() {
prop_dir="/data/android-data/property"
prop="persist.sys.usb.config"
prop_val="$1"
# Property value ordering is important here
grep -q -s mtp "$prop_dir/$prop" && [ "$prop_val" == "adb" ] && prop_val="mtp,adb"
grep -q -s adb "$prop_dir/$prop" && [ "$prop_val" == "mtp" ] && prop_val="mtp,adb"
property_write "$prop" "$prop_val"
}
usb_disable() {
prop_dir="/data/android-data/property"
prop="persist.sys.usb.config"
prop_val="$1"
remain_prop=""
# Property value ordering is important here
grep -q -s mtp "$prop_dir/$prop" && [ "$prop_val" == "adb" ] && remain_prop="mtp"
grep -q -s adb "$prop_dir/$prop" && [ "$prop_val" == "mtp" ] && remain_prop="adb"
# we should not allow empty properties for the usb config
[ "$remain_prop" == "" ] && remain_prop="adb"
property_write "$prop" "$remain_prop"
}
get_base_url() {
if [ -f /cache/recovery/base_url ]; then
cat /cache/recovery/base_url
# Store .base_url for OTA updates
cp /cache/recovery/base_url /data/.base_url
rm /cache/recovery/base_url
elif [ -f /data/.base_url ]; then
cat /data/.base_url
else
echo ""
fi
}
load_keyring() {
if [ -e /etc/system-image/$1.tar.xz ]; then
echo "Loading keyring: $1.tar.xz"
install_keyring /etc/system-image/$1.tar.xz /etc/system-image/$1.tar.xz.asc
fi
}
# Initialize GPG
rm -Rf /tmp/system-image
mkdir -p /tmp/system-image
case $(get_base_url) in
"http://system-image.tasemnice.eu"|"https://system-image.tasemnice.eu")
load_keyring archive-master-tasemnice
;;
"http://system-image.ubports.com"|"https://system-image.ubports.com")
load_keyring archive-master-ubports
;;
"http://kubuntu.plasma-mobile.org"|"https://kubuntu.plasma-mobile.org")
load_keyring archive-master-kubuntu
;;
*)
load_keyring archive-master
;;
esac
# Initialize recovery SWAP
## Without a swap some systems will fail to install the ubuntu rootfs (due its size)
if [ ! -e /cache/recovery/SWAP.img ]; then
dd if=/dev/zero of=/cache/recovery/SWAP.img bs=4096 count=8192
mkswap /cache/recovery/SWAP.img
fi
swapon /cache/recovery/SWAP.img || echo "Temporary swap setup failed! Does the kernel support swap?"
# Check the kernel command line to see whether Ubuntu should be installed to a partition
# or in a file that is loop mounted.
if grep -q systempart= /proc/cmdline; then
USE_SYSTEM_PARTITION=1
else
USE_SYSTEM_PARTITION=0
fi
# However, do not use the block device name in the kernel command line, as that is not consistently
# named in booting normal and recovery modes. Expect fstab to have a system mountpoint or use a fallback.
if [ "$USE_SYSTEM_PARTITION" -eq 1 ];then
SYSTEM_PARTITION=$(grep "/system" /etc/recovery.fstab |cut -f 1 -d\ )
#Fall back to emmc@android if there's no system in fstab
if [ "$SYSTEM_PARTITION" == "" ]; then
SYSTEM_PARTITION = "emmc@android"
fi
fi
# Process the command file
FULL_IMAGE=0
echo "Processing the command file"
while read line
do
set -- $line
case "$1" in
format)
echo "Formating: $2"
case "$2" in
system)
FULL_IMAGE=1
if [ "$USE_SYSTEM_PARTITION" -eq 1 ];then
make.ext4fs $SYSTEM_PARTITION
else
#system.img is the deprecated name for ubuntu.img, handle that too
rm -f /data/system.img
rm -f /data/ubuntu.img
dd if=/dev/zero of=/data/ubuntu.img seek=500K bs=4096 count=0
mkfs.ext2 -F /data/ubuntu.img
ln /data/ubuntu.img /data/system.img
fi
;;
data)
for entry in /data/* /data/.writable_image; do
if [ "$USE_SYSTEM_PARTITION" -eq 0 ];then
if [ "$entry" == "/data/system.img" -o "$entry" == "/data/ubuntu.img" ]; then
continue
fi
fi
rm -Rf $entry
done
# mtp is always enabled by default
usb_enable mtp
DATA_FORMAT=1
;;
*)
echo "Unknown format target: $2"
;;
esac
;;
enable)
echo "Enabling: $2"
case "$2" in
developer_mode)
usb_enable adb
;;
mtp)
usb_enable mtp
;;
default_password)
set_password $3
;;
*)
echo "Unknown enable target: $2"
;;
esac
;;
disable)
echo "Disabling: $2"
case "$2" in
developer_mode)
usb_disable adb
;;
mtp)
usb_disable mtp
;;
default_password)
unset_password
;;
*)
echo "Unknown disable target: $2"
;;
esac
;;
load_keyring)
if [ ! -e "/cache/recovery/$2" ] || [ ! -e "/cache/recovery/$3" ]; then
echo "Skipping missing file: $2"
continue
fi
REMOVE_LIST="$REMOVE_LIST /cache/recovery/$2 /cache/recovery/$3"
echo "Loading keyring: $2"
install_keyring /cache/recovery/$2 /cache/recovery/$3
if [ -e /tmp/system-image/image-master/pubring.gpg ] && \
[ ! -e /tmp/system-image/blacklist/pubring.gpg ] && \
[ -e /data/system-data/var/lib/system-image/blacklist.tar.xz ] && \
[ -e /data/system-data/var/lib/system-image/blacklist.tar.xz.asc ]; then
echo "Loading blacklist keyring"
install_keyring /data/system-data/var/lib/system-image/blacklist.tar.xz /data/system-data/var/lib/system-image/blacklist.tar.xz.asc
fi
;;
mount)
case "$2" in
system)
mkdir -p "$SYSTEM_MOUNTPOINT"
if [ "$USE_SYSTEM_PARTITION" -eq 1 ];then
mount $SYSTEM_PARTITION "$SYSTEM_MOUNTPOINT"
else
if [ ! -e /data/ubuntu.img ]; then
ln /data/system.img /data/ubuntu.img
fi
mount -o loop /data/ubuntu.img "$SYSTEM_MOUNTPOINT/"
fi
;;
*)
echo "Unknown mount target: $2"
;;
esac
;;
unmount)
case "$2" in
system)
sync
busybox umount -d "$SYSTEM_MOUNTPOINT"
rmdir "$SYSTEM_MOUNTPOINT"
;;
*)
echo "Unknown mount target: $2"
;;
esac
;;
update)
if [ ! -e "/cache/recovery/$2" ] || [ ! -e "/cache/recovery/$3" ]; then
echo "Skipping missing file: $2"
continue
fi
REMOVE_LIST="$REMOVE_LIST /cache/recovery/$2 /cache/recovery/$3"
if ! verify_signature device-signing /cache/recovery/$3 && \
! verify_signature image-signing /cache/recovery/$3; then
echo "Invalid signature"
continue
fi
echo "Applying update: $2"
cd /cache
rm -Rf partitions
# Start by removing any file listed in "removed"
if [ "$FULL_IMAGE" != "1" ]; then
cat recovery/$2 | unxz | tar xf - removed >/dev/null 2>&1 || true
if [ -e removed ]; then
while read file; do
rm -Rf $file
done < removed
fi
rm -f removed
fi
# Unpack everything else on top of the system partition
cat recovery/$2 | unxz | tar xf -
rm -f removed
if [ -e /etc/recovery.fstab ]; then
fstab_path="/etc/recovery.fstab"
elif [ -e /etc/recovery.fstab.bak ]; then
fstab_path="/etc/recovery.fstab.bak"
else
echo "Failed to find path to recovery.fstab!"
continue
fi
# Process partition images
while read line; do
set -- $line
part=${1##/}
path=$3
if [ -e partitions/${part}.img ] && [ -e $path ]; then
if [ ${part} = "boot" ]; then
echo "Flashing ${part} at ${path}"
cat partitions/${part}.img > ${path}
else
echo "Skipping partition update: ${part}"
fi
rm partitions/${part}.img
fi
done < $fstab_path
;;
*)
echo "Unknown command: $1"
;;
esac
done < $COMMAND_FILE
# Remove temporary SWAP
swapoff /cache/recovery/SWAP.img || true
rm -f /cache/recovery/SWAP.img
# Remove the update files
for file in $REMOVE_LIST; do
rm -f $file
done
# If a previous SWAP of 512MB is available, remove
if [ -e /data/SWAP.img ]; then
swap_size=`stat /data/SWAP.img | grep Size | awk -F' ' '{print $2}'`
if [ "$swap_size" = "536870912" ]; then
echo "Removing old 512MB swap file."
rm -f /data/SWAP.img
fi
fi
# Create the SWAP image if missing
# Here we only want a small SWAP to be created, as we found out
# that the kernel memory manager algorithm behaves better if swap
# is available, even if a minimal one (not to be used by the system)
if [ ! -e /data/SWAP.img ]; then
echo "Creating SWAP device (32MB)."
dd if=/dev/zero of=/data/SWAP.img bs=4096 count=8192
mkswap /data/SWAP.img
fi
# Ensure we have sane permissions
if [ "$USE_SYSTEM_PARTITION" -eq 0 ];then
chmod 600 /data/ubuntu.img
chown 0:0 /data/ubuntu.img
fi
chmod 600 /data/SWAP.img
chown 0:0 /data/SWAP.img
touch /data/.last_update || true
sync
echo "Done upgrading: $(date)"