blob: 5789f8323a930caf5784263f71c0ba1cf7cb4754 [file] [log] [blame]
#!/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 contains common constants and functions for installer scripts. This must
# evaluate properly for both /bin/bash and /bin/sh, since it's used both to
# create the initial image at compile time and to install or upgrade a running
# image.
# The GPT tables describe things in terms of 512-byte sectors, but some
# filesystems prefer 4096-byte blocks. These functions help with alignment
# issues.
# This returns the size of a file or device in 512-byte sectors, rounded up if
# needed.
# Invoke as: subshell
# Args: FILENAME
# Return: whole number of sectors needed to fully contain FILENAME
numsectors() {
if [ -b "${1}" ]; then
dev=${1##*/}
if [ -e /sys/block/$dev/size ]; then
cat /sys/block/$dev/size
else
part=${1##*/}
block=$(get_block_dev_from_partition_dev "${1}")
block=${block##*/}
cat /sys/block/$block/$part/size
fi
else
local bytes=$(stat -c%s "$1")
local sectors=$(( $bytes / 512 ))
local rem=$(( $bytes % 512 ))
if [ $rem -ne 0 ]; then
sectors=$(( $sectors + 1 ))
fi
echo $sectors
fi
}
# Round a number of 512-byte sectors up to an integral number of 2Mb
# blocks. Divisor is 2 * 1024 * 1024 / 512 == 4096.
# Invoke as: subshell
# Args: SECTORS
# Return: Next largest multiple-of-8 sectors (ex: 4->8, 33->40, 32->32)
roundup() {
local num=$1
local div=${2:-4096}
local rem=$(( $num % $div ))
if [ $rem -ne 0 ]; then
num=$(($num + $div - $rem))
fi
echo $num
}
# Truncate a number of 512-byte sectors down to an integral number of 2Mb
# blocks. Divisor is 2 * 1024 * 1024 / 512 == 4096.
# Invoke as: subshell
# Args: SECTORS
# Return: Next smallest multiple-of-8 sectors (ex: 4->0, 33->32, 32->32)
rounddown() {
local num=$1
local div=${2:-4096}
local rem=$(( $num % $div ))
if [ $rem -ne 0 ]; then
num=$(($num - $rem))
fi
echo $num
}
# Locate the cgpt tool. It should already be installed in the build chroot,
# but some of these functions may be invoked outside the chroot (by
# image_to_usb or similar), so we need to find it.
GPT=""
locate_gpt() {
if [ -z "$GPT" ]; then
if [ -x "${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt" ]; then
GPT="${DEFAULT_CHROOT_DIR:-}/usr/bin/cgpt"
else
GPT=$(which cgpt 2>/dev/null) || /bin/true
if [ -z "$GPT" ]; then
echo "can't find cgpt tool" 1>&2
exit 1
fi
fi
fi
}
# Read GPT table to find the starting location of a specific partition.
# Invoke as: subshell
# Args: DEVICE PARTNUM
# Returns: offset (in sectors) of partition PARTNUM
partoffset() {
sudo $GPT show -b -i $2 $1
}
# Read GPT table to find the size of a specific partition.
# Invoke as: subshell
# Args: DEVICE PARTNUM
# Returns: size (in sectors) of partition PARTNUM
partsize() {
sudo $GPT show -s -i $2 $1
}
# Extract the whole disk block device from the partition device.
# This works for /dev/sda3 (-> /dev/sda) as well as /dev/mmcblk0p2
# (-> /dev/mmcblk0).
get_block_dev_from_partition_dev() {
local partition=$1
if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
echo "Invalid partition name: $partition" >&2
exit 1
fi
# Removes any trailing digits.
local block=$(echo "$partition" | sed -e 's/[0-9]*$//')
# If needed, strip the trailing 'p'.
if (expr match "$block" ".*[0-9]p$" >/dev/null); then
echo "${block%p}"
else
echo "$block"
fi
}
# Extract the partition number from the partition device.
# This works for /dev/sda3 (-> 3) as well as /dev/mmcblk0p2 (-> 2).
get_partition_number() {
local partition=$1
if ! (expr match "$partition" ".*[0-9]$" >/dev/null) ; then
echo "Invalid partition name: $partition" >&2
exit 1
fi
# Extract the last digit.
echo "$partition" | sed -e 's/^.*\([0-9]\)$/\1/'
}
# Construct a partition device name from a whole disk block device and a
# partition number.
# This works for [/dev/sda, 3] (-> /dev/sda3) as well as [/dev/mmcblk0, 2]
# (-> /dev/mmcblk0p2).
make_partition_dev() {
local block=$1
local num=$2
# If the disk block device ends with a number, we add a 'p' before the
# partition number.
if (expr match "$block" ".*[0-9]$" >/dev/null) ; then
echo "${block}p${num}"
else
echo "${block}${num}"
fi
}
# Find the uuid for a (disk, partnum) pair (e.g., ("/dev/sda", 3))
part_index_to_uuid() {
local dev="$1"
local idx="$2"
sudo $GPT show -i "$idx" -u "$dev"
}
list_usb_disks() {
local sd
for sd in /sys/block/sd*; do
if readlink -f ${sd}/device | grep -q usb &&
[ "$(cat ${sd}/removable)" = 1 -a "$(cat ${sd}/size)" != 0 ]; then
echo ${sd##*/}
fi
done
}
list_mmc_disks() {
local mmc
for mmc in /sys/block/mmcblk*; do
if readlink -f ${mmc}/device | grep -q mmc; then
echo ${mmc##*/}
fi
done
}
get_disk_info() {
# look for a "given" file somewhere in the path upwards from the device
local dev_path=/sys/block/${1}/device
while [ -d "${dev_path}" -a "${dev_path}" != "/sys" ]; do
if [ -f "${dev_path}/${2}" ]; then
cat "${dev_path}/${2}"
return
fi
dev_path=$(readlink -f ${dev_path}/..)
done
echo '[Unknown]'
}
legacy_offset_size_export() {
# Exports all the variables that install_gpt did previously.
# This should disappear eventually, but it's here to make existing
# code work for now.
START_STATEFUL=$(partoffset $1 1)
START_KERN_A=$(partoffset $1 2)
START_ROOTFS_A=$(partoffset $1 3)
START_KERN_B=$(partoffset $1 4)
START_ROOTFS_B=$(partoffset $1 5)
START_OEM=$(partoffset $1 8)
START_RWFW=$(partoffset $1 11)
START_ESP=$(partoffset $1 12)
NUM_STATEFUL_SECTORS=$(partsize $1 1)
NUM_KERN_SECTORS=$(partsize $1 2)
NUM_ROOTFS_SECTORS=$(partsize $1 3)
NUM_OEM_SECTORS=$(partsize $1 8)
NUM_RWFW_SECTORS=$(partsize $1 11)
NUM_ESP_SECTORS=$(partsize $1 12)
STATEFUL_IMG_SECTORS=$(partsize $1 1)
KERNEL_IMG_SECTORS=$(partsize $1 2)
ROOTFS_IMG_SECTORS=$(partsize $1 3)
OEM_IMG_SECTORS=$(partsize $1 8)
ESP_IMG_SECTORS=$(partsize $1 12)
}
install_hybrid_mbr() {
# Creates a hybrid MBR which points the MBR partition 1 to GPT
# partition 12 (ESP). This is useful on ARM boards that boot
# from MBR formatted disks only
echo "Creating hybrid MBR"
locate_gpt
local start_esp=$(partoffset "$1" 12)
local num_esp_sectors=$(partsize "$1" 12)
sudo sfdisk "${1}" <<EOF
unit: sectors
disk1 : start= $start_esp, size= $num_esp_sectors, Id= c, bootable
disk2 : start= 1, size= 1, Id= ee
EOF
}