#!/bin/sh
#
# debeagle - Install Debian on a Beagle SBC
#
# Copyright (C) 2014 Patrick "P. J." McDermott
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
set -u
main()
{
local opt=
local mirror=
local suite=
local target=
while getopts 'm:' opt; do
case ${opt} in
m) mirror="${OPTARG}";;
?)
print_usage >&2
exit 1
;;
esac
done
shift $(($OPTIND - 1))
case ${#} in
1)
suite="${1}"
target=''
;;
2)
suite="${1}"
target="${2}"
;;
*)
print_usage >&2
exit 1
;;
esac
make_parts_and_fs "${target}"
install_debian "${mirror}" "${suite}" "${target}"
}
print_usage()
{
printf 'Usage: %s [-m ] []\n' "${0}"
}
error()
{
local status=${1}
local fmt="${2}"
shift 2
printf "Error: ${fmt}\n" "${@}" >&2
exit ${status}
}
_select()
{
# Field width of the prompt numbers.
select_width=$(expr ${#} : '.*')
select_i=
while :; do
case "${select_i}" in
'')
select_i=0
for select_word in "${@}"; do
select_i=$(expr ${select_i} + 1)
printf "%${select_width}d) %s\\n" \
${select_i} "${select_word}" \
>&2
done
;;
*[!0-9]*)
printf 'Please enter a number in range.\n' >&2
;;
*)
if [ ${select_i} -gt 0 ] && \
[ ${select_i} -le ${#} ]; then
shift $(expr $select_i - 1)
select_result="${1}"
break
fi
printf 'Please enter a number in range.\n' >&2
;;
esac
# Prompt and read input.
printf '%s' "${PS3-#? }" >&2
read -r select_i || exit
done
}
pretty_print_size_dec()
{
local size="${1}"
awk -v size=${size} 'BEGIN {
split("B KB MB GB TB", units, " ");
i=1;
while (size >= 1000) {
size /= 1000;
++i;
};
printf("%.2f %s\n", size, units[i]); }'
}
pretty_print_size_bin()
{
local size="${1}"
awk -v size=${size} 'BEGIN {
split("B KiB MiB GiB TiB", units, " ");
i=1;
while (size >= 1024) {
size /= 1024;
++i;
};
printf("%.2f %s\n", size, units[i]); }'
}
get_block_dev_name()
{
local dev="${1}"
local vendor=
local model=
if [ -e "/sys/block/${dev}/device/vendor" ]; then
vendor="$(cat "/sys/block/${dev}/device/vendor")"
model="$(cat "/sys/block/${dev}/device/model")"
name="${vendor} ${model}"
else
name="$(cat "/sys/block/${dev}/device/name")"
fi
printf '%s' "${name}"
}
prompt_block_dev()
{
local dev=
local name=
local size=
local size_s=
local desc=
local devs=
set --
for dev in /sys/block/*; do
dev="${dev#/sys/block/}"
case "${dev}" in
loop*|sr*) continue;;
esac
name="$(get_block_dev_name "${dev}")"
size="$(cat "/sys/block/${dev}/size")"
size="$(expr ${size} \* 512)"
size_s="$(pretty_print_size_dec "${size}")"
size_s="${size_s} ($(pretty_print_size_bin "${size}"))"
desc="$(printf '%s (%s) - %s\n' "${name}" "${dev}" "${size_s}")"
set -- "${@}" "${desc}"
devs="$(printf '%s\n%s\t%s\n' "${devs}" "${desc}" "${dev}")"
done
printf 'Select a block device:\n' >&2
_select "${@}"
while IFS=' ' read -r desc dev; do
if [ "x${desc}" = "x${select_result}" ]; then
printf '%s\n' "${dev}"
fi
done <<-EOF
${devs}
EOF
}
make_parts_and_fs()
{
local target="${1}"
local part_prefix=''
if [ "x${target}" = 'x' ]; then
target="/dev/$(prompt_block_dev)"
elif [ -e "/sys/block/${target#/dev/}" ]; then
printf 'Installing to %s\n' \
"$(get_block_dev_name "${target#/dev/}")"
else
error 1 'Device %s not found\n' "${target}"
fi
if grep "^${target}" /proc/mounts >/dev/null 2>&1; then
error 1 'File system(s) on device %s mounted\n' "${target}"
fi
dd if=/dev/zero of="${target}" bs=512 count=1
sfdisk -u S "${target}" <<-EOF
,102400,0x0E,*
,,0x83,-
EOF
case "${target}" in
/dev/mmcblk*) part_prefix='p';;
esac
mkdosfs -F 16 "${target}${part_prefix}1"
mke2fs -t ext4 "${target}${part_prefix}2"
}
install_debian()
{
local mirror="${1}"
local suite="${2}"
local target="${3}"
local part_prefix=''
local boot_mp=''
local root_mp=''
local archives=''
local linux_version=''
case "${target}" in
/dev/mmcblk*) part_prefix='p';;
esac
boot_mp="$(mktemp -d)"
root_mp="$(mktemp -d)"
mount -o 'iocharset=iso8859-1' "${target}${part_prefix}1" "${boot_mp}"
mount "${target}${part_prefix}2" "${root_mp}"
debootstrap --arch=armhf --include=linux-image-armmp,u-boot-omap \
--foreign "${suite}" "${root_mp}" ${mirror}
archives="${root_mp}/var/cache/apt/archives"
ar p "${archives}/"u-boot-omap_*_armhf.deb data.tar.xz | \
tar -xJO ./usr/lib/u-boot/omap3_beagle/MLO \
>"${boot_mp}/MLO"
ar p "${archives}/"u-boot-omap_*_armhf.deb data.tar.xz | \
tar -xJO ./usr/lib/u-boot/omap3_beagle/u-boot.bin \
>"${boot_mp}/u-boot.img"
cat >"${boot_mp}/uEnv.txt" <<-EOF
mpurate=1000
dvimode="hd720 omapfb.vram=0:8M,1:4M,2:4M"
vram=16M
optargs="consoleblank=0"
console="tty0 console=ttyO2,115200n8"
EOF
linux_version="$(printf '%s\n' \
"${archives}/"linux-image-*-armmp_*_armhf.deb | sed \
"s|^${archives}/linux-image-\\(.*-armmp\\)_.*\$|\1|")"
(
cd "${root_mp}"
ar p var/cache/apt/archives/linux-image-*-armmp_*.deb \
data.tar.xz | tar -xJ
)
mkimage -A arm -O linux -T kernel -C none \
-a 0x80008000 -e 0x80008000 -n "Linux ${linux_version}" \
-d "${root_mp}/boot/vmlinuz-${linux_version}" \
"${root_mp}/boot/uImage"
cp "${root_mp}/boot/uImage" "${boot_mp}/uImage"
umount "${boot_mp}"
umount "${root_mp}"
rmdir "${boot_mp}"
rmdir "${root_mp}"
}
main "${@}"