| #!/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 |