| #!/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-2023 by The BRLTTY Developers. | |
| # | |
| # BRLTTY comes with ABSOLUTELY NO WARRANTY. | |
| # | |
| # This is free software, placed under the terms of the | |
| # GNU Lesser General Public License, as published by the Free Software | |
| # Foundation; either version 2.1 of the License, or (at your option) any | |
| # later version. Please see the file LICENSE-LGPL for details. | |
| # | |
| # Web Page: http://brltty.app/ | |
| # | |
| # 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 |