#!/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 "${@}"