#!/bin/bash -p ############################################################################### # BRLTTY - A background process providing access to the console screen (when in # text mode) for a blind person using a refreshable braille display. # # Copyright (C) 1995-2011 by The BRLTTY Developers. # # BRLTTY comes with ABSOLUTELY NO WARRANTY. # # This is free software, placed under the terms of the # GNU General Public License, as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any # later version. Please see the file LICENSE-GPL for details. # # Web Page: http://mielke.cc/brltty/ # # This software is maintained by Dave Mielke <dave@mielke.cc>. ############################################################################### programName="${0##*/}" programMessage() { echo >&2 "${programName}: ${1}" } programError() { [ -n "${1}" ] && programMessage "${1}" exit "${2:-3}" } syntaxError() { programError "${1}" 2 } mount_ext2() { mount -o loop -t ext2 "${2}" "${1}" } unmount_ext2() { umount "${1}" } check_ext2() { set -- $(stat -c '%a %s' -f -- "${initrdRoot}") initrdAvailableBlocks="${1}" initrdBlockSize="${2}" set -- $(du --block-size="${initrdBlockSize}" -s "${brlttyInstallRoot}") brlttyInstallBlocks="${1}" set -- $(stat -c '%s' -- "${initrdImage}") initrdImageBytes="${1}" initrdImageBlocks=$(( (initrdImageBytes + initrdBlockSize - 1) / initrdBlockSize )) initrdPadBlocks=$(( brlttyInstallBlocks - initrdAvailableBlocks )) (( (initrdPadBlocks += 200) > 0 )) && { initrdMounted=false "unmount_${initrdType}" "${initrdRoot}" "${initrdImage}" dd bs="${initrdBlockSize}" count="${initrdPadBlocks}" if="/dev/zero" of="${initrdImage}" seek="${initrdImageBlocks}" e2fsck -y -f "${initrdImage}" && resize2fs "${initrdImage}" || { newImage="${temporaryDirectory}/new.${initrdType}" cp -RpPd -- "${initrdImage}" "${newImage}" mke2fs -q -b "${initrdBlockSize}" -F "${newImage}" newRoot="${temporaryDirectory}/new" mkdir "${newRoot}" "mount_${initrdType}" "${newRoot}" "${newImage}" newMounted=true "mount_${initrdType}" "${initrdRoot}" "${initrdImage}" initrdMounted=true cp -RpPd -- "${initrdRoot}/." "${newRoot}" initrdMounted=false "unmount_${initrdType}" "${initrdRoot}" "${initrdImage}" newMounted=false "unmount_${initrdType}" "${newRoot}" "${newImage}" cp -- "${newImage}" "${initrdImage}" } "mount_${initrdType}" "${initrdRoot}" "${initrdImage}" initrdMounted=true } } mount_cpio() { cd "${1}" cpio --quiet -i -I "${2}" cd "${workingDirectory}" } unmount_cpio() { cd "${1}" [ -n "${2}" ] && { find . -print | sed -e '/^\.$/d' -e 's/^\.\///' | cpio --quiet -o -H newc -O "${2}" } rm -f -r -- $(ls -1 -A) cd "${workingDirectory}" } check_cpio() { : } originalImage="boot.iso" modifiedImage="brltty.iso" brlttyPattern="brltty-*" brailleDrivers="all" textTable="en-nabcc" invokeShell=false showUsage() { cat <<EOF Usage: ${programName} [-option ...] The following options are supported: -i file The original (input) image (default: ${originalImage}). -o file The modified (output) image (default: ${modifiedImage}). -a file The BRLTTY archive (default: ${brlttyPattern}). -b driver,... The braille driver(s) to include (default: ${brailleDrivers}). -t file The text table to build in (default: ${textTable}). -s Invoke an interactive shell to inspect the modified image. -h Display usage information and exit. EOF exit 0 } while getopts ":i:o:a:b:t:sh" option do case "${option}" in i) originalImage="${OPTARG}";; o) modifiedImage="${OPTARG}";; a) brlttyPattern="${OPTARG}";; b) brailleDrivers="${OPTARG}";; t) textTable="${OPTARG}";; s) invokeShell=true;; h) showUsage;; \?) syntaxError "unknown option: -${OPTARG}";; :) syntaxError "missing operand: -${OPTARG}";; *) syntaxError "unimplemented option: -${option}";; esac done shift $((OPTIND - 1)) [ "${#}" -gt 0 ] && syntaxError "too many parameters." [ -f "${originalImage}" ] || programError "original image not found: ${originalImage}" shopt -s nullglob extglob set -- $brlttyPattern [ "${#}" -eq 0 ] && programError "brltty archive not found: ${brlttyPattern}" [ "${#}" -gt 1 ] && { brlttyArchives="$(echo "${*}" | sed -e 's% %,&%g')" programError "more than one brltty archive: ${brlttyArchives}" } brlttyArchive="${1}" cleanup() { set +e cd / "${newMounted}" && "unmount_${initrdType}" "${newRoot}" "${initrdMounted}" && "unmount_${initrdType}" "${initrdRoot}" "${originalMounted}" && umount "${originalRoot}" [ -n "${temporaryDirectory}" ] && rm -r "${temporaryDirectory}" } set -e originalMounted=false initrdMounted=false newMounted=false trap "cleanup" 0 workingDirectory="${PWD}" temporaryDirectory="$(mktemp -d "${TMPDIR:-/tmp}/${programName}.XXXXXX")" originalRoot="${temporaryDirectory}/original" mkdir "${originalRoot}" mount -o loop -t iso9660 "${originalImage}" "${originalRoot}" originalMounted=true modifiedRoot="${temporaryDirectory}/modified" mkdir "${modifiedRoot}" cp -RpPd -- "${originalRoot}/." "${modifiedRoot}" loaderDirectory="" for directory in boot/isolinux isolinux do [ -d "${originalRoot}/${directory}" ] && { loaderDirectory="${directory}" break } done configurationFile="isolinux.cfg" sed -n -e ' 1i\ prompt 1\ timeout 0\ default text\ /^ *prompt /d /^ *timeout /d /^ *default /d /^ *menu *default *$/d /^ *append.* text/s/$/ nofb/ /^ *append.* rescue/s/$/ text nofb/ p ' <"${originalRoot}/${loaderDirectory}/${configurationFile}" >"${modifiedRoot}/${loaderDirectory}/${configurationFile}" # bootMessage="boot.msg" # echo -n -e '\a' >"${modifiedRoot}/${loaderDirectory}/${bootMessage}" # cat "${originalRoot}/${loaderDirectory}/${bootMessage}" >>"${modifiedRoot}/${loaderDirectory}/${bootMessage}" initrdImage="${temporaryDirectory}/initrd.img" initrdPath="${modifiedRoot}/${loaderDirectory}/initrd.img" gunzip -c "${initrdPath}" >"${initrdImage}" initrdDescription="`file -b "${initrdImage}"`" case "${initrdDescription}" in *" ext2 "*) initrdType=ext2;; *" cpio "*) initrdType=cpio;; *) programError "unsupported initrd image format: ${initrdDescription}" esac initrdRoot="${temporaryDirectory}/initrd" mkdir "${initrdRoot}" "mount_${initrdType}" "${initrdRoot}" "${initrdImage}" initrdMounted=true found=false for name in linuxrc init do linuxrcPath="${initrdRoot}/${name}" initPath="$(readlink "${linuxrcPath}")" && { found=true break } done "${found}" || programError "linuxrc not found." rm "${linuxrcPath}" ln -s /bin/brltty "${linuxrcPath}" deviceDirectory="${initrdRoot}/dev" ensureDevices() { typeset type="${1}" typeset major="${2}" typeset minor="${3}" typeset prefix="${4}" typeset last="${5}" typeset suffix="${6}" typeset number=0 while ((number <= last)) do typeset path="${deviceDirectory}/${prefix}${suffix}" [ -e "${path}" ] || mknod -m 600 "${path}" "${type}" "${major}" "$((minor++))" suffix=$((++number)) done } ensureDevices c 7 0 vcs 12 ensureDevices c 7 128 vcsa 12 ensureDevices c 5 1 console 0 ensureDevices c 4 0 tty 12 0 ensureDevices c 4 64 ttyS 3 0 ensureDevices c 188 0 ttyUSB 1 0 case "${brlttyArchive}" in *.tar.gz|*.tgz) tar x -z -C "${temporaryDirectory}" -f "${brlttyArchive}" ;; *.tar) tar x -C "${temporaryDirectory}" -f "${brlttyArchive}" ;; *) programError "unsupported brltty archive name: ${brlttyArchive}" ;; esac shopt -s nullglob set -- ${temporaryDirectory}/brltty* [ "${#}" -eq 0 ] && programError "brltty build directory not found." brlttyBuildRoot="${1}" brlttyInstallRoot="${temporaryDirectory}/install" ( set -e trap "" 0 cd "${brlttyBuildRoot}" shopt -s nullglob set -- ./autogen* for autogen do [ -f "${autogen}" -a -r "${autogen}" -a -x "${autogen}" ] && "${autogen}" done ./configure --quiet --with-install-root="${brlttyInstallRoot}" \ --with-init-path="${initPath}" --with-stderr-path="/dev/tty5" \ --with-writable-directory="/tmp" \ --with-screen-driver="lx,-all" \ --with-braille-driver="-tt,-vr,${brailleDrivers}" \ --with-text-table="${textTable}" \ --disable-speech-support --without-libbraille --without-curses --disable-x \ --disable-pcm-support --disable-fm-support --disable-midi-support \ --enable-standalone-programs --disable-api --disable-gpm --disable-icu make -s -C Programs all strip Programs/brltty make -s -C Programs install-programs install-data-files install-tables ) || exit "${?}" "check_${initrdType}" ( set -e cd "${brlttyInstallRoot}" cp --parents -- $(find . -type f -printf '%P ') "${initrdRoot}" ) || exit 1 "${invokeShell}" && ( set +e trap "" 0 cd "${temporaryDirectory}" "${SHELL:-/bin/sh}" exit 0 ) initrdMounted=false "unmount_${initrdType}" "${initrdRoot}" "${initrdImage}" gzip -c -9 "${initrdImage}" >"${initrdPath}" isoVolumeIdentifier="$(isoinfo -d -i "${originalImage}" | grep '^Volume id:' | cut -d' ' -f3-)" isoApplicationIdentifier="$(isoinfo -d -i "${originalImage}" | grep '^Application id:' | cut -d' ' -f3-)" mkisofs -quiet -J -R -T -boot-load-size 4 -boot-info-table -no-emul-boot \ -A "${isoApplicationIdentifier}" -V "${isoVolumeIdentifier}" \ -b "${loaderDirectory}/isolinux.bin" -c "${loaderDirectory}/boot.cat" \ -o "${modifiedImage}" "${modifiedRoot}" exit 0