blob: 554a6cd45976657bec65d117d70d9b366e4482c5 [file] [log] [blame]
#!/bin/sh
#
# Volume check service
#
. /etc/utils.sh
sata_blkdev=$(find_sata_blkdev)
platform=$(cat /etc/platform)
# 'data+ubi' partition
DATA_MTD_NAME='"data+ubi"'
DATA_MTD_NO=
DRM0_MTD_NAME='"drmregion0"'
DRM0_MTD_NO=
DRM1_MTD_NAME='"drmregion1"'
DRM1_MTD_NO=
# 'rootfs' on /dev/ubi0
# 'data+ubi' on /dev/ubi1
DATA_UBI_NO=1
# eMMC support
DATA_MMC_NAME="data+ext4"
ATV_DATA_MMC_NAME="userdata"
ATV_HWCFG_MMC_NAME="hwcfg"
DRM_FS_NAME="drmfs1"
DRM_FS_RECOVER_NAME="drmfs2"
USER_NAME=user
CONFIG_NAME=config
CONFIG_SIZE=$((16*1024*1024)) # 16MiB
USER_SIZE=0
BADBLOCK_FILE=/tmp/gpio/ledcontrol/flash_bad_blocks
check_mtd()
{
local a b c d e
cat /proc/mtd |
while read a b c d; do
# convert 'mtdxx:' to 'xx'
e=${a%:*}
[ $d = $1 ] && echo "${e#mtd}"
done
}
get_mtd_size()
{
local a b c d e
cat /proc/mtd |
while read a b c d; do
e=${a%:*}
[ "${e#mtd}" = "$1" ] && printf "%d" 0x${b}
done
}
check_mmc()
{
local result=
sgdisk -p /dev/mmcblk0 >/tmp/mmcpart
while read number start end size unit code name; do
if [ "$name" = "$1" ]; then
result=$number
fi
done </tmp/mmcpart
rm -f /tmp/mmcpart
[ -n "$result" ] && echo "$result"
}
fail()
{
echo "$(basename $0):" "$@" >&2
[ -f $BADBLOCK_FILE ] || echo "" >$BADBLOCK_FILE
}
recover_volume()
{
# Format MTD device and mount UBI volumes.
# $1 - MTD device number
# $2 - UBI device number
echo "Failed to mount ubifs on mtd$1, formatting..."
# umount UBI volumes detach UBI devices
umount_ubifs $2
# format MTD partition
ubiformat /dev/mtd$1 -y
# attach UBI devices and mount UBI volumes
mount_ubifs $1 $2
}
mount_ubifs()
{
# Attach MTD device to UBI device.
# $1 - MTD device number
# $2 - UBI device number
#echo "Attach mtd$1 to /dev/ubi$2"
# If UBI device failed to attach, return 1 to call 'recover_volume()':
# 1. detach UBI devices
# 2. erase MTD partition
# 3. format MTD partition
# 4. attach UBI devices and mount UBI volumes again
ubiattach -m $1 -d $2
if [ $? -eq 0 ]; then
mount_volumes $1 $2 || return 1
else
echo "Failed to attach mtd$1 to /dev/ubi$2"
return 1
fi
}
mount_volumes()
{
# Mount UBI volumes.
# $1 - MTD device number
# $2 - UBI device number
if [ $1 -eq ${DATA_MTD_NO} ]; then
# For platforms with a single, small MTD partition;
# (ie gfrg240) create a single /user partition and
# have /config reside under /user.
actual_size=$(get_mtd_size $1)
if [ "${actual_size}" -gt "${CONFIG_SIZE}" ]; then
# mount UBI 'config' volume
mount_volume "${CONFIG_NAME}" "$2" "${CONFIG_SIZE}" || return 1
# mount UBI 'user' volume
mount_volume "${USER_NAME}" "$2" "${USER_SIZE}" || return 1
else
# mount UBI 'user' volume
mount_volume "${USER_NAME}" "$2" "${USER_SIZE}" || return 1
# bring /config under /user
mkdir -p "/${USER_NAME}/${CONFIG_NAME}"
mount --bind "/${USER_NAME}/${CONFIG_NAME}" "/${CONFIG_NAME}" || return 1
fi
fi
}
mount_volume()
{
# Mount UBI volume.
# $1 - UBI volume name
# $2 - UBI device number
# $3 - UBI volume size
# make UBI volume
make_volume $1 $2 $3 || return 1
# mount UBI volume
[ ! -d /$1 ] && mkdir -p /$1
if ! mount -o chk_data_crc -t ubifs ubi$2:$1 /$1; then
echo "Failed to mount '$1' volume"
return 1
fi
}
make_volume()
{
# Make UBI volume.
# $1 - UBI volume name
# $2 - UBI device number
# $3 - UBI volume size
# get UBI volume name and remove 'space' characters
if ubinfo -d $2 -N $1; then
echo "UBI volume '$1' exists"
return 0
fi
# echo "Make '$1' volume on /dev/ubi$2 (size:$3)"
if [ $3 = "0" ]; then
size_args="-m"
else
size_args="-s $3"
fi
if ! ubimkvol /dev/ubi$2 ${size_args} -N $1; then
echo "Failed to make '$1' volume"
return 1
fi
}
umount_ubifs()
{
# Umount UBI volumes.
# $1 - UBI device number
if [ $1 -eq ${DATA_UBI_NO} ]; then
[ -d /${USER_NAME} ] && umount /${USER_NAME}
[ -d /${CONFIG_NAME} ] && umount /${CONFIG_NAME}
else
return 1
fi
sleep 1
ubidetach -d $1
}
mount_drmfs_ro()
{
# TODO(jnewlin): Making this mount rw for a few builds.
# The first batch of EVT2 boards has unbound keyboxes so we need
# this writable so the keybox gets bound when oregano starts.
mount -t ext4 -o rw,defaults $1 $2 || return 1
}
mount_hwcfg_ro()
{
mount -t cramfs -o ro,relatime,barrier=1 $1 $2 || return 1
}
# $1 : primary drmfs
# $2 : secondary drmfs
recover_drmfs()
{
e2fsck $1 || mkfs.ext4 $1 || return 1
mkdir -p /tmp/drmfs_primary
mkdir -p /tmp/drmfs_secondary
mount -t ext4 -o ro,defaults $2 /tmp/drmfs_secondary || return 1
mount -t ext4 -o defaults $1 /tmp/drmfs_primary || return 1
# TODO(jnewlin): Need to revisit with real keybox name.
cp /tmp/drmfs_secondary/drm.bin /tmp/drmfs_primary/drm.bin
umount /tmp/drmfs_primary
umount /tmp/drmfs_secondary
mount_drmfs_ro $1 /user/drmfs
}
mount_ext4fs()
{
# Use ordered mode & disable delayed allocation to enable metadata journaling
# and ensure data blocks are always written before metadata. Avoids issues
# with power loss or crashes resulting in zero length files.
mount -t ext4 -o defaults,noatime,discard,nodelalloc,data=ordered $1 /user || return 1
[ ! -d /user/config ] && mkdir -p /user/config
mount --bind /user/config /config || return 1
}
mount_atv_ext4fs()
{
mount -t ext4 -o defaults,noatime,discard,nodelalloc,data=ordered $1 /atv_userdata || return 1
mkdir -p /atv_userdata/gfiber/user
mount --bind /atv_userdata/gfiber/user /user || return 1
mkdir -p /user/config
mount --bind /user/config /config || return 1
}
recover_ext4fs()
{
e2fsck $1 || mkfs.ext4 -E discard -m 2 -L ${DATA_MMC_NAME} $1
mount_ext4fs $1
}
recover_atv_ext4fs()
{
e2fsck $1 || mkfs.ext4 -E discard -m 2 -L ${ATV_DATA_MMC_NAME} $1
mount_atv_ext4fs $1
}
case "$1" in
start)
wait-scsi & # pre-start this so later scripts can use the result
# Get MTD partition number
DATA_MTD_NO=$(check_mtd ${DATA_MTD_NAME})
DRM0_MTD_NO=$(check_mtd ${DRM0_MTD_NAME})
DRM1_MTD_NO=$(check_mtd ${DRM1_MTD_NAME})
# Log bbinfo at boot
BBT=""
cat /proc/sys/dev/repartition/bbinfo |
while read a b ; do
BBT="$BBT$a$b "
done
echo "Bad Blocks: $BBT"
if [ ! -z "${DATA_MTD_NO}" ]; then
mount_ubifs ${DATA_MTD_NO} ${DATA_UBI_NO} || \
recover_volume ${DATA_MTD_NO} ${DATA_UBI_NO}
else
DATA_MMC_NO=$(check_mmc ${DATA_MMC_NAME})
if [ -n "${DATA_MMC_NO}" ]; then
DATA_BLK_NAME=/dev/mmcblk0p${DATA_MMC_NO}
echo "Found non-ATV partition table ${DATA_MMC_NAME} at ${DATA_BLK_NAME}!"
if [ -b ${DATA_BLK_NAME} ]; then
mount_ext4fs ${DATA_BLK_NAME} || recover_ext4fs ${DATA_BLK_NAME}
fi
else
# try if this is a dual-boot Android TV system
ATV_DATA_MMC_NO=$(check_mmc ${ATV_DATA_MMC_NAME})
if [ -n "${ATV_DATA_MMC_NO}" ]; then
ATV_DATA_BLK_NAME=/dev/mmcblk0p${ATV_DATA_MMC_NO}
echo "Found ATV partition table ${ATV_DATA_MMC_NAME} at ${ATV_DATA_BLK_NAME}!"
if [ -b ${ATV_DATA_BLK_NAME} ]; then
mount_atv_ext4fs ${ATV_DATA_BLK_NAME} || \
recover_atv_ext4fs ${ATV_DATA_BLK_NAME}
fi
else
echo "Error-Could not find either ${DATA_MMC_NAME} or ${ATV_DATA_MMC_NAME}"
fi
fi
fi
# Fix access permissions on drm partitions
if [ ! -z "${DRM0_MTD_NO}" ]; then
chown appclient:appclient /dev/mtd${DRM0_MTD_NO}
chown appclient:appclient /dev/mtdblock${DRM0_MTD_NO}
fi
if [ ! -z "${DRM1_MTD_NO}" ]; then
chown appclient:appclient /dev/mtd${DRM1_MTD_NO}
chown appclient:appclient /dev/mtdblock${DRM1_MTD_NO}
fi
[ ! -d /user/rw ] && mkdir -p /user/rw
[ ! -d /user/bsa ] && mkdir -p /user/bsa
[ ! -d /user/netflix ] && mkdir -p /user/netflix
[ ! -d /user/vudu ] && mkdir -p /user/vudu
[ ! -d /user/drm ] && mkdir -p /user/drm
[ ! -d /user/widevine ] && mkdir -p /user/widevine
[ ! -d /user/ytlb ] && mkdir -p /user/ytlb
[ ! -d /tmp/vudu ] && mkdir -p /tmp/vudu
[ ! -d /tmp/oprofile ] && mkdir -p /tmp/oprofile
if has-drm-fs; then
# create folder for SAGE usage tables if not present
[ ! -d /user/widevine/brcm_sage ] && mkdir -p /user/widevine/brcm_sage && chmod 777 /user/widevine/brcm_sage
[ ! -d /user/drmfs ] && mkdir -p /user/drmfs
ATV_HWCFG_MMC_NO=$(check_mmc ${ATV_HWCFG_MMC_NAME})
DRMFS_MOUNTED=0 # not mounted yet
if [ -n "${ATV_HWCFG_MMC_NO}" ]; then
ATV_HWCFG_BLK_NAME=/dev/mmcblk0p${ATV_HWCFG_MMC_NO}
echo "Found ATV partition table ${ATV_HWCFG_MMC_NAME} at ${ATV_HWCFG_BLK_NAME}!"
if [ -b ${ATV_HWCFG_BLK_NAME} ]; then
if mount_hwcfg_ro ${ATV_HWCFG_BLK_NAME} /user/drmfs; then
DRMFS_MOUNTED=1
else
echo "failed mounting ${ATV_HWCFG_BLK_NAME}"
fi
fi
fi
if [ ${DRMFS_MOUNTED} -eq 0 ]; then
DRM_FS_MMC_NO=$(check_mmc ${DRM_FS_NAME})
DRM_FS_RECOVER_MMC_NO=$(check_mmc ${DRM_FS_RECOVER_NAME})
DRM_FS_BLK_NAME=/dev/mmcblk0p${DRM_FS_MMC_NO}
DRM_FS_RECOVER_BLK_NAME=/dev/mmcblk0p${DRM_FS_RECOVER_MMC_NO}
if [ -b ${DRM_FS_BLK_NAME} ]; then
if ! mount_drmfs_ro ${DRM_FS_BLK_NAME} /user/drmfs; then
echo "DRMFS is corrupt, attempting to recover keybox..."
if ! recover_drmfs ${DRM_FS_BLK_NAME} ${DRM_FS_RECOVER_BLK_NAME}; then
echo "DRMFS is corrupted and not recoverable."
fi
fi
fi
fi
fi
rm -rf /user/diag/diagdb.bin /user/diag/*.tmp /user/diag/log
# /config must be writeable by non-root
chown bin.sys /config
chmod 775 /config
# Application data must be owned by appclient
chown -R appclient.appclient /user/netflix
chown -R appclient.appclient /user/vudu
chown -R appclient.appclient /user/drm
chown -R appclient.appclient /user/widevine
chown -R appclient.appclient /user/ytlb
chown -R appclient.appclient /tmp/vudu
# Application user must be able to write kmsg with logos
chmod 622 /dev/kmsg
if [ -e "$sata_blkdev" ]; then
(
smartctl -A "$sata_blkdev"
smartctl -t short "$sata_blkdev"
sleep 60
smartctl -l selftest "$sata_blkdev"
) 2>&1 | logos smartctl &
fi
if [ -e /config/DEBUG ]; then
echo "Enabling DEBUG mode because /config/DEBUG is set." >&2
echo >/tmp/DEBUG
fi
;;
stop)
# Get MTD partition number
DATA_MTD_NO=$(check_mtd ${DATA_MTD_NAME})
umount_ubifs ${DATA_UBI_NO}
;;
restart|reload)
;;
*)
echo "Usage: $0 {start|stop|restart}" >&2
exit 1
esac