From 8897610d955ca87b3cc705343f09e837f7a96ce1 Mon Sep 17 00:00:00 2001 From: "T. Joseph Carter" Date: Tue, 25 Oct 2016 12:09:52 -0700 Subject: [PATCH] Scripts: re-indent (tab indentation) One of the reasons I held off on doing this before is that there are a lot of complex one-line seds in here that I expect _will_ be broken by this. More than a few of these will assume, depend on, require, and break if specific hardcoded whitespace is not found. That's problematic anyway--when whitespace isn't syntactic, you shouldn't do that. So it's time to fix these anyway. --- files/dist/getexternal.sh | 52 +- files/netatalk-init.d-clean.txt | 48 +- fix/fix.txt | 183 +-- scripts/a2server-1-storage.txt | 24 +- scripts/a2server-2-tools.txt | 246 ++-- scripts/a2server-3-sharing.txt | 934 ++++++------- scripts/a2server-5-netboot.txt | 1986 +++++++++++++------------- scripts/a2server-6-samba.txt | 130 +- scripts/a2server-7-console.txt | 16 +- scripts/raspbian-update.txt | 335 ++--- scripts/tools/a2server-aliases.txt | 2 +- scripts/tools/a2serverrc.txt | 2 +- scripts/tools/afpsync.txt | 176 +-- scripts/tools/afptype.txt | 552 ++++---- scripts/tools/cppo.txt | 2088 ++++++++++++++-------------- scripts/tools/mkatinit.txt | 398 +++--- scripts/tools/mkvolinfo.txt | 130 +- setup/index.txt | 514 +++---- update/index.txt | 24 +- 19 files changed, 3921 insertions(+), 3919 deletions(-) diff --git a/files/dist/getexternal.sh b/files/dist/getexternal.sh index 9e1a681..94c4067 100755 --- a/files/dist/getexternal.sh +++ b/files/dist/getexternal.sh @@ -1,8 +1,8 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: if ! hash wget; then - echo "wget is not installed. On a Mac, install it with MacPorts or Homebrew." + echo "wget is not installed. On a Mac, install it with MacPorts or Homebrew." fi echo "Downloading items..." @@ -37,30 +37,30 @@ wget -O files/external/appleii/sam2.bxy "$samUrl" wget -O files/external/appleii/snap.bxy "$snapUrl" for gsosInstall in {1..3}; do - activeDisk=0 - mkdir -p files/external/appleii/gsos60${gsosInstall} + activeDisk=0 + mkdir -p files/external/appleii/gsos60${gsosInstall} - diskNames=( Install System.Disk SystemTools1 SystemTools2 Fonts synthLAB ) - if (( $gsosInstall == 1 )); then - gsosURL="http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_IIGS_System_6.0.1/" - wget --max-redirect 0 -O files/external/appleii/gsos601/Disk_7_of_7-Apple_II_Setup.sea.bin http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_IIGS_System_6.0.1/Disk_7_of_7-Apple_II_Setup.sea.bin - elif (( $gsosInstall == 2 )); then - gsosURL="http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Software/Operating%20Systems/Apple%20IIGS%20System/Disk%20Images/" - diskNames=( Install System.Disk SystemTools1 SystemTools2 SystemTools3 Fonts1 Fonts2 synthLAB ) - diskWebNames=( Install System%20disk System%20tools%201 System%20tools%202 System%20tools%203 Fonts%201 Fonts%202 Synthlab ) - elif (( $gsosInstall == 3 )); then - gsosURL="ftp://ftp.apple.asimov.net/pub/apple_II/images/gs/os/gsos/Apple_IIGS_System_6.0.3/" - fi + diskNames=( Install System.Disk SystemTools1 SystemTools2 Fonts synthLAB ) + if (( $gsosInstall == 1 )); then + gsosURL="http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_IIGS_System_6.0.1/" + wget --max-redirect 0 -O files/external/appleii/gsos601/Disk_7_of_7-Apple_II_Setup.sea.bin http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_IIGS_System_6.0.1/Disk_7_of_7-Apple_II_Setup.sea.bin + elif (( $gsosInstall == 2 )); then + gsosURL="http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Software/Operating%20Systems/Apple%20IIGS%20System/Disk%20Images/" + diskNames=( Install System.Disk SystemTools1 SystemTools2 SystemTools3 Fonts1 Fonts2 synthLAB ) + diskWebNames=( Install System%20disk System%20tools%201 System%20tools%202 System%20tools%203 Fonts%201 Fonts%202 Synthlab ) + elif (( $gsosInstall == 3 )); then + gsosURL="ftp://ftp.apple.asimov.net/pub/apple_II/images/gs/os/gsos/Apple_IIGS_System_6.0.3/" + fi - for diskname in ${diskNames[@]}; do - outfile="files/external/appleii/gsos60${gsosInstall}/$diskname.po" - (( activeDisk++ )) - if (( $gsosInstall == 1 )); then - wget --max-redirect 0 -O files/external/appleii/gsos601/"Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${gsosURL}Disk_${activeDisk}_of_7-${diskname}.sea.bin" - elif (( $gsosInstall == 2 )); then - wget -O $outfile "$gsosURL/IIGS%20System%206.0.2%20-%20Disk%20${activeDisk}%20${diskWebNames[$activeDisk-1]}.po" - elif (( $gsosInstall == 3 )); then - wget -O $outfile "$gsosURL/$diskname.po" - fi - done + for diskname in ${diskNames[@]}; do + outfile="files/external/appleii/gsos60${gsosInstall}/$diskname.po" + (( activeDisk++ )) + if (( $gsosInstall == 1 )); then + wget --max-redirect 0 -O files/external/appleii/gsos601/"Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${gsosURL}Disk_${activeDisk}_of_7-${diskname}.sea.bin" + elif (( $gsosInstall == 2 )); then + wget -O $outfile "$gsosURL/IIGS%20System%206.0.2%20-%20Disk%20${activeDisk}%20${diskWebNames[$activeDisk-1]}.po" + elif (( $gsosInstall == 3 )); then + wget -O $outfile "$gsosURL/$diskname.po" + fi + done done diff --git a/files/netatalk-init.d-clean.txt b/files/netatalk-init.d-clean.txt index 9021990..185ba86 100755 --- a/files/netatalk-init.d-clean.txt +++ b/files/netatalk-init.d-clean.txt @@ -45,7 +45,7 @@ HOSTNAME=`/bin/hostname` # Read in netatalk configuration. if [ -f /etc/default/netatalk ]; then - . /etc/default/netatalk + . /etc/default/netatalk fi # Start Netatalk servers. @@ -53,9 +53,9 @@ atalk_startup() { if [ x"$ATALKD_RUN" = x"yes" ]; then # Try to load the AppleTalk kernel module if it was intended. - if grep -q '^appletalk$' /etc/modules; then + if grep -q '^appletalk$' /etc/modules; then /sbin/modprobe appletalk || echo "[could not load appletalk module]" - fi + fi # Start atalkd server. /usr/local/sbin/atalkd @@ -70,8 +70,8 @@ atalk_startup() { # prepare startup of file services if [ "x$CNID_METAD_RUN" = "xyes" -a -x /usr/local/sbin/cnid_metad ] ; then echo -n " cnid_metad" - /usr/local/sbin/cnid_metad $CNID_CONFIG - fi + /usr/local/sbin/cnid_metad $CNID_CONFIG + fi if [ x"$AFPD_RUN" = x"yes" ]; then /usr/local/sbin/afpd $AFPD_UAMLIST -g $AFPD_GUEST -c $AFPD_MAX_CLIENTS \ @@ -79,17 +79,17 @@ atalk_startup() { echo -n " afpd" fi - if [ "x$ATALKD_RUN" = "xyes" ]; then - if [ "x$PAPD_RUN" = "xyes" ]; then - /usr/local/sbin/papd - echo -n " papd" - fi + if [ "x$ATALKD_RUN" = "xyes" ]; then + if [ "x$PAPD_RUN" = "xyes" ]; then + /usr/local/sbin/papd + echo -n " papd" + fi - if [ x"$TIMELORD_RUN" = x"yes" ]; then - /usr/local/sbin/timelord - echo -n " timelord" - fi - fi + if [ x"$TIMELORD_RUN" = x"yes" ]; then + /usr/local/sbin/timelord + echo -n " timelord" + fi + fi } case "$1" in @@ -113,19 +113,19 @@ case "$1" in start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/cnid_metad if test -x /usr/local/sbin/papd; then - echo -n " papd" - start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/papd - fi + echo -n " papd" + start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/papd + fi if test -x /usr/local/sbin/timelord; then - echo -n " timelord" - start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/timelord - fi + echo -n " timelord" + start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/timelord + fi if test -x /usr/local/sbin/atalkd; then - echo -n " atalkd" - start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/atalkd - fi + echo -n " atalkd" + start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/atalkd + fi echo "." ;; diff --git a/fix/fix.txt b/fix/fix.txt index b5f8c3c..d90682a 100644 --- a/fix/fix.txt +++ b/fix/fix.txt @@ -1,4 +1,5 @@ #!/bin/bash +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: echo echo "A2SERVER fix: This utility will make a Raspberry Pi SD card boot if it" @@ -9,106 +10,106 @@ echo -n "Continue? " read doFix= if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then - while true; do - echo - echo "If attached, remove the Raspberry Pi's SD card from this computer." - echo -n "Press return to continue..."; read; echo + while true; do + echo + echo "If attached, remove the Raspberry Pi's SD card from this computer." + echo -n "Press return to continue..."; read; echo - ls -1 /dev/sd? > /tmp/sd1 2> /dev/null + ls -1 /dev/sd? > /tmp/sd1 2> /dev/null - echo "Insert the Raspberry Pi's SD card into this computer, using a USB" - echo "reader if you don't have an SD slot. If this is a virtual machine," - echo "make sure you select the reader or SD slot from its USB menu." - echo -n "Press return to continue..."; read; echo + echo "Insert the Raspberry Pi's SD card into this computer, using a USB" + echo "reader if you don't have an SD slot. If this is a virtual machine," + echo "make sure you select the reader or SD slot from its USB menu." + echo -n "Press return to continue..."; read; echo - ls -1 /dev/sd? > /tmp/sd2 2> /dev/null + ls -1 /dev/sd? > /tmp/sd2 2> /dev/null - # if exactly one drive has been inserted, exit loop - if { ! diff /tmp/sd1 /tmp/sd2 &> /dev/null; }; then - # files are different, get dev name - if [[ $(wc -c /tmp/sd1 | cut -f 1 -d ' ') -eq 0 ]]; then - if [[ $(wc -l /tmp/sd2 | cut -f 1 -d ' ') -eq 1 ]]; then - devName=$(cat /tmp/sd2) - break - else - echo "More than one volume seems to have appeared. Trying again..." - echo - fi - else - devName=$(grep -v "$(cat /tmp/sd1)" /tmp/sd2) - if [[ $(wc -l <<< $devName) -eq 1 ]]; then - break - else - echo "More than one volume seems to have appeared. Trying again..." - echo - fi - fi - else - echo "No SD card found. Trying again..." - echo - fi + # if exactly one drive has been inserted, exit loop + if { ! diff /tmp/sd1 /tmp/sd2 &> /dev/null; }; then + # files are different, get dev name + if [[ $(wc -c /tmp/sd1 | cut -f 1 -d ' ') -eq 0 ]]; then + if [[ $(wc -l /tmp/sd2 | cut -f 1 -d ' ') -eq 1 ]]; then + devName=$(cat /tmp/sd2) + break + else + echo "More than one volume seems to have appeared. Trying again..." + echo + fi + else + devName=$(grep -v "$(cat /tmp/sd1)" /tmp/sd2) + if [[ $(wc -l <<< $devName) -eq 1 ]]; then + break + else + echo "More than one volume seems to have appeared. Trying again..." + echo + fi + fi + else + echo "No SD card found. Trying again..." + echo + fi - done + done - mkdir -p /tmp/sd - sudo mount ${devName}6 /tmp/sd + mkdir -p /tmp/sd + sudo mount ${devName}6 /tmp/sd - raspbianDate=$(date -d "$(zcat /tmp/sd/usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | grep -m 1 ' --' | rev | cut -f 1-6 -d ' ' | rev)" +%s) - doFix= - if [[ $raspbianDate -lt 1403204265 ]]; then - echo "This doesn't appear to be a version of Raspbian that requires fixing." - echo -n "Are you sure you want to continue? " - read - if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then - doFix=1 - fi - else - doFix=1 - fi + raspbianDate=$(date -d "$(zcat /tmp/sd/usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | grep -m 1 ' --' | rev | cut -f 1-6 -d ' ' | rev)" +%s) + doFix= + if [[ $raspbianDate -lt 1403204265 ]]; then + echo "This doesn't appear to be a version of Raspbian that requires fixing." + echo -n "Are you sure you want to continue? " + read + if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then + doFix=1 + fi + else + doFix=1 + fi - if [[ $doFix ]]; then - while read kernelRelease; do - kernelReplaced= - kernelMajorRelease=$(cut -d '.' -f 1 <<< $kernelRelease) - kernelMinorRelease=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') - kernelPatchRelease=$(cut -d '.' -f 3- <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') - # if kernel 3.12 below 3.12.25+, delete defective AppleTalk kernel - if [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -eq 12 && $kernelPatchRelease -lt 25 ]]; then - if [[ -f /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then - if [[ $(sha1sum /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then - echo "Removing defective AppleTalk module from kernel $kernelRelease..." - sudo rm -rf /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null - wget -qO /tmp/appletalk.ko.gz ${A2SERVER_SCRIPT_URL}files/appletalk-$kernelRelease.ko.gz - if [[ $? -eq 0 ]]; then - # if we found a prebuilt one on a2server site, so install it - gunzip -f /tmp/appletalk.ko.gz - sudo mkdir -p /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk - sudo mv /tmp/appletalk.ko /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk - echo "Installed fixed AppleTalk module for kernel $kernelRelease." - kernelReplaced=1 - fi - fi - fi - fi - done <<< "$(ls -1 /tmp/sd/lib/modules | sort -V)" - sudo umount /tmp/sd + if [[ $doFix ]]; then + while read kernelRelease; do + kernelReplaced= + kernelMajorRelease=$(cut -d '.' -f 1 <<< $kernelRelease) + kernelMinorRelease=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') + kernelPatchRelease=$(cut -d '.' -f 3- <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') + # if kernel 3.12 below 3.12.25+, delete defective AppleTalk kernel + if [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -eq 12 && $kernelPatchRelease -lt 25 ]]; then + if [[ -f /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then + if [[ $(sha1sum /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then + echo "Removing defective AppleTalk module from kernel $kernelRelease..." + sudo rm -rf /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null + wget -qO /tmp/appletalk.ko.gz ${A2SERVER_SCRIPT_URL}files/appletalk-$kernelRelease.ko.gz + if [[ $? -eq 0 ]]; then + # if we found a prebuilt one on a2server site, so install it + gunzip -f /tmp/appletalk.ko.gz + sudo mkdir -p /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk + sudo mv /tmp/appletalk.ko /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk + echo "Installed fixed AppleTalk module for kernel $kernelRelease." + kernelReplaced=1 + fi + fi + fi + fi + done <<< "$(ls -1 /tmp/sd/lib/modules | sort -V)" + sudo umount /tmp/sd - echo kern:$kernelReplaced - if [[ $kernelReplaced ]]; then - echo - echo "All set. Remove your SD card, put it back in your Pi, and boot it." - echo - echo "You should be able to connect from your Apple II, but if you can't," - echo "log in to your Pi and type 'a2server-setup' to complete the fix." - else - echo - echo "Okey doke. Half done. Remove your SD card, and put it back in your Pi." - echo "After it boots, log in and type 'a2server-setup' to complete the fix." - fi - echo "See the A2SERVER web site at http://ivanx.com/a2server for more help." - echo "(You can type 'sudo shutdown -h now' if you're done on this machine.)" - echo - fi + echo kern:$kernelReplaced + if [[ $kernelReplaced ]]; then + echo + echo "All set. Remove your SD card, put it back in your Pi, and boot it." + echo + echo "You should be able to connect from your Apple II, but if you can't," + echo "log in to your Pi and type 'a2server-setup' to complete the fix." + else + echo + echo "Okey doke. Half done. Remove your SD card, and put it back in your Pi." + echo "After it boots, log in and type 'a2server-setup' to complete the fix." + fi + echo "See the A2SERVER web site at http://ivanx.com/a2server for more help." + echo "(You can type 'sudo shutdown -h now' if you're done on this machine.)" + echo + fi fi rm fix &> /dev/null diff --git a/scripts/a2server-1-storage.txt b/scripts/a2server-1-storage.txt index e2cdbd2..f078974 100755 --- a/scripts/a2server-1-storage.txt +++ b/scripts/a2server-1-storage.txt @@ -1,31 +1,31 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # --- Setting up the share volume # 1.3.0: move /media/A2SHARED (pre-1.3.0) to /srv/A2SERVER if [[ -d /media/A2SHARED ]]; then - echo "A2SERVER: Moving /media/A2SHARED to /srv/A2SERVER..." - sudo /etc/init.d/netatalk stop &> /dev/null - sudo /etc/init.d/samba stop &> /dev/null - [[ ! -d /srv ]] && sudo mkdir -p /srv - sudo mv /media/A2SHARED /srv/A2SERVER - sudo sed -i 's|/media/A2SHARED|/srv/A2SERVER|g' /usr/local/etc/netatalk/AppleVolumes.default - [[ -f /etc/samba/smbd.conf ]] && sudo sed -i 's|/media/A2SHARED|/srv/A2SERVER|g' /etc/samba/smbd.conf + echo "A2SERVER: Moving /media/A2SHARED to /srv/A2SERVER..." + sudo /etc/init.d/netatalk stop &> /dev/null + sudo /etc/init.d/samba stop &> /dev/null + [[ ! -d /srv ]] && sudo mkdir -p /srv + sudo mv /media/A2SHARED /srv/A2SERVER + sudo sed -i 's|/media/A2SHARED|/srv/A2SERVER|g' /usr/local/etc/netatalk/AppleVolumes.default + [[ -f /etc/samba/smbd.conf ]] && sudo sed -i 's|/media/A2SHARED|/srv/A2SERVER|g' /etc/samba/smbd.conf fi # skip if we're already set up if [[ -d /srv/A2SERVER ]]; then - echo "A2SERVER: Shared volume is already prepared for use." + echo "A2SERVER: Shared volume is already prepared for use." else - echo "A2SERVER: Preparing the shared files volume..." + echo "A2SERVER: Preparing the shared files volume..." - sudo mkdir -p /srv/A2SERVER + sudo mkdir -p /srv/A2SERVER - sudo chown $USER:$USER /srv/A2SERVER + sudo chown $USER:$USER /srv/A2SERVER fi diff --git a/scripts/a2server-2-tools.txt b/scripts/a2server-2-tools.txt index 382f155..0644f89 100755 --- a/scripts/a2server-2-tools.txt +++ b/scripts/a2server-2-tools.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # download and install a2server tools: # mkatinit, mkvolinfo, afptype, afpsync, aliases, nulib2 @@ -20,90 +20,90 @@ debianVersion=$(cat /etc/debian_version 2> /dev/null) isRpi= arch= if [[ -f /usr/bin/raspi-config ]]; then - isRpi=1 - arch='rpi' + isRpi=1 + arch='rpi' elif lsb_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ $(cut -d . -f 1 <<< $debianVersion) -ge "7" ]]; then - uname_m="$(uname -m)" - if [[ $uname_m == "i686" ]]; then - arch='debian_x86' - elif [[ $uname_m == "x86_64" ]]; then - arch='debian_x64' - fi + uname_m="$(uname -m)" + if [[ $uname_m == "i686" ]]; then + arch='debian_x86' + elif [[ $uname_m == "x86_64" ]]; then + arch='debian_x64' + fi fi debianName= if [[ $debianVersion ]]; then - debianMajor=$(cut -d . -f 1 <<< $debianVersion) - if [[ $debianMajor == "8" ]]; then - debianName="jessie" - elif [[ $debianMajor == "7" ]]; then - debianName="wheezy" - else - debianName="unknown" - fi + debianMajor=$(cut -d . -f 1 <<< $debianVersion) + if [[ $debianMajor == "8" ]]; then + debianName="jessie" + elif [[ $debianMajor == "7" ]]; then + debianName="wheezy" + else + debianName="unknown" + fi fi echo "A2SERVER: Installing A2SERVER tools..." # delete older nulib2 which doesn't correctly handle zero-length forks in GSHK-created archives if hash nulib2 &> /dev/null; then - nulib2version=$(nulib2 | sed -n 2p | sed 's|^.*v\([0-9]\)\.\([0-9]\)\.\([0-9]\).*$|\1\2\3|' 2> /dev/null) - if (( $nulib2version < 310 )); then - sudo apt-get -y purge nulib2 &> /dev/null - sudo rm $(command -v nulib2) &> /dev/null - fi + nulib2version=$(nulib2 | sed -n 2p | sed 's|^.*v\([0-9]\)\.\([0-9]\)\.\([0-9]\).*$|\1\2\3|' 2> /dev/null) + if (( $nulib2version < 310 )); then + sudo apt-get -y purge nulib2 &> /dev/null + sudo rm $(command -v nulib2) &> /dev/null + fi fi if ! hash nulib2 &> /dev/null; then - echo "A2SERVER: Installing nulib2..." + echo "A2SERVER: Installing nulib2..." - cd /tmp - if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then - { wget -qO- "${binaryURL}precompiled/nulib2-3.1.0a2-${arch}.tgz" | sudo tar Pzx; } &> /dev/null - fi + cd /tmp + if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then + { wget -qO- "${binaryURL}precompiled/nulib2-3.1.0a2-${arch}.tgz" | sudo tar Pzx; } &> /dev/null + fi - if ! hash nulib2 &> /dev/null; then + if ! hash nulib2 &> /dev/null; then - if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then - # prepare for installing packages - sudo apt-get -y update - touch /tmp/a2server-packageReposUpdated - fi + if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then + # prepare for installing packages + sudo apt-get -y update + touch /tmp/a2server-packageReposUpdated + fi - # Dependencies: build-dep for nulib - sudo apt-get -y install build-essential zlib1g-dev - sudo apt-get -y clean + # Dependencies: build-dep for nulib + sudo apt-get -y install build-essential zlib1g-dev + sudo apt-get -y clean - cd /tmp - rm -rf /tmp/nulib2 &> /dev/null - mkdir /tmp/nulib2 - cd /tmp/nulib2 - if [[ $useExternalURL ]]; then - wget -q -O nulib2-3.1.0a2.zip "https://github.com/fadden/nulib2/archive/20fe7efb4d37fedf807416c16d74d51d893ea48a.zip" - unzip nulib2-3.1.0a2.zip 2> /dev/null - rm nulib2-3.1.0a2.zip &> /dev/null - fi - if [ ! -d nulib2* ]; then - wget -q -O nulib2-3.1.0a2.zip "${binaryURL}external/source/nulib2-3.1.0a2.zip" - unzip nulib2-3.1.0a2.zip 2> /dev/null - rm nulib2-3.1.0a2.zip &> /dev/null - fi - cd nulib2* - cd nufxlib - ./configure - make - sudo make install - cd ../nulib2 - ./configure - make - sudo make install - cd - rm -rf /tmp/nulib2 - fi + cd /tmp + rm -rf /tmp/nulib2 &> /dev/null + mkdir /tmp/nulib2 + cd /tmp/nulib2 + if [[ $useExternalURL ]]; then + wget -q -O nulib2-3.1.0a2.zip "https://github.com/fadden/nulib2/archive/20fe7efb4d37fedf807416c16d74d51d893ea48a.zip" + unzip nulib2-3.1.0a2.zip 2> /dev/null + rm nulib2-3.1.0a2.zip &> /dev/null + fi + if [ ! -d nulib2* ]; then + wget -q -O nulib2-3.1.0a2.zip "${binaryURL}external/source/nulib2-3.1.0a2.zip" + unzip nulib2-3.1.0a2.zip 2> /dev/null + rm nulib2-3.1.0a2.zip &> /dev/null + fi + cd nulib2* + cd nufxlib + ./configure + make + sudo make install + cd ../nulib2 + ./configure + make + sudo make install + cd + rm -rf /tmp/nulib2 + fi else - echo "A2SERVER: Nulib2 has already been installed." + echo "A2SERVER: Nulib2 has already been installed." fi # download and install The Unarchiver, for expanding Apple disk images @@ -111,73 +111,73 @@ fi if ! hash unar &> /dev/null; then - echo "A2SERVER: Installing The Unarchiver..." + echo "A2SERVER: Installing The Unarchiver..." - if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then - # prepare for installing packages - sudo apt-get -y update - touch /tmp/a2server-packageReposUpdated - fi + if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then + # prepare for installing packages + sudo apt-get -y update + touch /tmp/a2server-packageReposUpdated + fi - # jessie and later: Just use the unar package - if [[ $debianMajor -ge 8 ]]; then - sudo apt-get -y install unar - sudo apt-get clean - fi + # jessie and later: Just use the unar package + if [[ $debianMajor -ge 8 ]]; then + sudo apt-get -y install unar + sudo apt-get clean + fi - if ! hash unar &> /dev/null; then - if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then - # Dependencies: for unar - sudo apt-get -y install libgnustep-base1.22 - sudo apt-get clean - { wget -qO- "${binaryURL}precompiled/unar-${arch}_${debianName}.tgz" | sudo tar Pzx; } &> /dev/null - fi + if ! hash unar &> /dev/null; then + if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then + # Dependencies: for unar + sudo apt-get -y install libgnustep-base1.22 + sudo apt-get clean + { wget -qO- "${binaryURL}precompiled/unar-${arch}_${debianName}.tgz" | sudo tar Pzx; } &> /dev/null + fi - # If all else fails, compile from source. - if ! hash unar &> /dev/null; then + # If all else fails, compile from source. + if ! hash unar &> /dev/null; then - # Dependencies: build-deps for unar - sudo apt-get -y install build-essential libgnustep-base-dev libz-dev libbz2-dev libssl-dev libicu-dev unzip - sudo apt-get clean + # Dependencies: build-deps for unar + sudo apt-get -y install build-essential libgnustep-base-dev libz-dev libbz2-dev libssl-dev libicu-dev unzip + sudo apt-get clean - rm -rf /tmp/unar &> /dev/null - mkdir /tmp/unar - cd /tmp/unar - if [[ $useExternalURL ]]; then - wget -O unar-1.8.1.zip https://github.com/incbee/Unarchiver/archive/unar-1.8.1.zip - unzip -o unar-1.8.1.zip &> /dev/null - fi - if [ ! -d *Unarchiver*/XADMaster ]; then # need single bracket for glob - wget -O unar-1.8.1.zip ${binaryURL}external/source/unar-1.8.1.zip - unzip -o unar-1.8.1.zip &> /dev/null - fi - cd *Unarchiver*/XADMaster - make -f Makefile.linux - sudo mv lsar unar /usr/local/bin - cd ../Extra - sudo mv lsar.1 unar.1 /usr/local/man/man1 - cd - rm -rf /tmp/unar - fi - sudo mandb &> /dev/null - fi + rm -rf /tmp/unar &> /dev/null + mkdir /tmp/unar + cd /tmp/unar + if [[ $useExternalURL ]]; then + wget -O unar-1.8.1.zip https://github.com/incbee/Unarchiver/archive/unar-1.8.1.zip + unzip -o unar-1.8.1.zip &> /dev/null + fi + if [ ! -d *Unarchiver*/XADMaster ]; then # need single bracket for glob + wget -O unar-1.8.1.zip ${binaryURL}external/source/unar-1.8.1.zip + unzip -o unar-1.8.1.zip &> /dev/null + fi + cd *Unarchiver*/XADMaster + make -f Makefile.linux + sudo mv lsar unar /usr/local/bin + cd ../Extra + sudo mv lsar.1 unar.1 /usr/local/man/man1 + cd + rm -rf /tmp/unar + fi + sudo mandb &> /dev/null + fi else - echo "A2SERVER: The Unarchiver has already been installed." + echo "A2SERVER: The Unarchiver has already been installed." fi if ! hash unzip &> /dev/null; then - echo "A2SERVER: Installing unzip..." - if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then - # prepare for installing packages - sudo apt-get -y update - touch /tmp/a2server-packageReposUpdated - fi + echo "A2SERVER: Installing unzip..." + if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then + # prepare for installing packages + sudo apt-get -y update + touch /tmp/a2server-packageReposUpdated + fi - # Dependencies: unzip - sudo apt-get -y install unzip - sudo apt-get clean + # Dependencies: unzip + sudo apt-get -y install unzip + sudo apt-get clean else - echo "A2SERVER: unzip has already been installed." + echo "A2SERVER: unzip has already been installed." fi sudo wget -q -O /usr/local/bin/afpsync "${scriptURL}scripts/tools/afpsync.txt" @@ -203,9 +203,9 @@ echo "source /usr/local/etc/a2serverrc" | sudo tee -a /etc/bash.bashrc > /dev/nu motd="/etc/motd" if [[ ! $(grep A2SERVER $motd) ]]; then - echo | sudo tee -a $motd > /dev/null - echo "Type 'system-shutdown' to turn off A2SERVER." | sudo tee -a $motd > /dev/null - echo "Type 'a2server-setup' to configure network boot." | sudo tee -a $motd > /dev/null - echo "Type 'a2server-help' for a list of other commands." | sudo tee -a $motd > /dev/null - echo | sudo tee -a $motd > /dev/null + echo | sudo tee -a $motd > /dev/null + echo "Type 'system-shutdown' to turn off A2SERVER." | sudo tee -a $motd > /dev/null + echo "Type 'a2server-setup' to configure network boot." | sudo tee -a $motd > /dev/null + echo "Type 'a2server-help' for a list of other commands." | sudo tee -a $motd > /dev/null + echo | sudo tee -a $motd > /dev/null fi diff --git a/scripts/a2server-3-sharing.txt b/scripts/a2server-3-sharing.txt index 2e669e6..9cb09a5 100755 --- a/scripts/a2server-3-sharing.txt +++ b/scripts/a2server-3-sharing.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # A2SERVER -- a virtual machine for sharing files to Apple II clients # by Ivan X, ivan@ivanx.com @@ -30,204 +30,204 @@ debianVersion=$(cat /etc/debian_version 2> /dev/null) isRpi= arch= if [[ -f /usr/bin/raspi-config ]]; then - isRpi=1 - arch='rpi' + isRpi=1 + arch='rpi' elif lsb_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ $(cut -d . -f 1 <<< $debianVersion) -ge "7" ]]; then - uname_m="$(uname -m)" - if [[ $uname_m == "i686" ]]; then - arch='debian_x86' - elif [[ $uname_m == "x86_64" ]]; then - arch='debian_x64' - fi + uname_m="$(uname -m)" + if [[ $uname_m == "i686" ]]; then + arch='debian_x86' + elif [[ $uname_m == "x86_64" ]]; then + arch='debian_x64' + fi fi debianName= if [[ $debianVersion ]]; then - debianMajor=$(cut -d . -f 1 <<< $debianVersion) - if [[ $debianMajor == "8" ]]; then - debianName="jessie" - elif [[ $debianMajor == "7" ]]; then - debianName="wheezy" - else - debianName="unknown" - fi + debianMajor=$(cut -d . -f 1 <<< $debianVersion) + if [[ $debianMajor == "8" ]]; then + debianName="jessie" + elif [[ $debianMajor == "7" ]]; then + debianName="wheezy" + else + debianName="unknown" + fi fi # skip this if already done if [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) >= 101 )); then - echo "A2SERVER: Netatalk is already installed." + echo "A2SERVER: Netatalk is already installed." else - echo "A2SERVER: Installing Netatalk (this will take a while)..." + echo "A2SERVER: Installing Netatalk (this will take a while)..." - # stop Netatalk and samba if running (during upgrade) - if [[ $(ps --no-headers -C afpd) ]]; then - sudo /etc/init.d/netatalk stop &> /dev/null - sudo /etc/init.d/samba stop &> /dev/null - fi + # stop Netatalk and samba if running (during upgrade) + if [[ $(ps --no-headers -C afpd) ]]; then + sudo /etc/init.d/netatalk stop &> /dev/null + sudo /etc/init.d/samba stop &> /dev/null + fi - if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then - # prepare for installing packages - sudo apt-get -y update - touch /tmp/a2server-packageReposUpdated - fi + if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then + # prepare for installing packages + sudo apt-get -y update + touch /tmp/a2server-packageReposUpdated + fi - # not being used as of 1.2.9, but it's available if full URL to .deb package is supplied - getOldPackage () { - for url in $@; do - pkgFile=${url##*/} - pkgName=${pkgFile%%_*} - if ! dpkg -l $pkgName 2> /dev/null | grep -q '^ii'; then - if [[ $useExternalURL ]]; then - wget -qO "/tmp/${url##*/}" "$url" - fi - if [[ $? -ne 0 || ! -f "/tmp/${url##*/}" ]]; then - wget -qO "/tmp/${url##*/}" "${binaryURL}external/deb/${url##*/}" - fi - sudo dpkg -i "/tmp/${url##*/}" - sudo apt-get clean - rm "/tmp/${url##*/}" - fi - done - } + # not being used as of 1.2.9, but it's available if full URL to .deb package is supplied + getOldPackage () { + for url in $@; do + pkgFile=${url##*/} + pkgName=${pkgFile%%_*} + if ! dpkg -l $pkgName 2> /dev/null | grep -q '^ii'; then + if [[ $useExternalURL ]]; then + wget -qO "/tmp/${url##*/}" "$url" + fi + if [[ $? -ne 0 || ! -f "/tmp/${url##*/}" ]]; then + wget -qO "/tmp/${url##*/}" "${binaryURL}external/deb/${url##*/}" + fi + sudo dpkg -i "/tmp/${url##*/}" + sudo apt-get clean + rm "/tmp/${url##*/}" + fi + done + } - compileFromSource=1 - urls= - while [[ $arch ]]; do - # Install runtime libraries needed by Netatalk - if [[ $(apt-cache search '^libdb5.1$') ]]; then # Wheezy - # Dependencies: netatalk 2.2.4 - sudo apt-get -y install libdb5.1 - elif [[ $(apt-cache search '^libdb5.3$') ]]; then # Jessie - # Dependencies: netatalk 2.2.4 - sudo apt-get -y install libdb5.3 - else - break - fi - if [[ $(apt-cache search '^libssl1.0.0$') ]]; then - # Dependencies: netatalk 2.2.4 - sudo apt-get -y install libssl1.0.0 - else - break - fi + compileFromSource=1 + urls= + while [[ $arch ]]; do + # Install runtime libraries needed by Netatalk + if [[ $(apt-cache search '^libdb5.1$') ]]; then # Wheezy + # Dependencies: netatalk 2.2.4 + sudo apt-get -y install libdb5.1 + elif [[ $(apt-cache search '^libdb5.3$') ]]; then # Jessie + # Dependencies: netatalk 2.2.4 + sudo apt-get -y install libdb5.3 + else + break + fi + if [[ $(apt-cache search '^libssl1.0.0$') ]]; then + # Dependencies: netatalk 2.2.4 + sudo apt-get -y install libssl1.0.0 + else + break + fi - if [[ $(apt-cache search '^libgcrypt11$') ]]; then # Wheezy - # Dependencies: netatalk 2.2.4 - sudo apt-get -y install libgcrypt11 - elif [[ $(apt-cache search '^libgcrypt20$') ]]; then # Jessie - # Dependencies: netatalk 2.2.4 - sudo apt-get -y install libgcrypt20 - else - break - fi + if [[ $(apt-cache search '^libgcrypt11$') ]]; then # Wheezy + # Dependencies: netatalk 2.2.4 + sudo apt-get -y install libgcrypt11 + elif [[ $(apt-cache search '^libgcrypt20$') ]]; then # Jessie + # Dependencies: netatalk 2.2.4 + sudo apt-get -y install libgcrypt20 + else + break + fi - # install Netatalk - if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then - { wget -qO- "${binaryURL}precompiled/netatalk224-${arch}_${debianName}.tgz" | sudo tar Pzx; } &> /dev/null - fi - sudo mandb &> /dev/null + # install Netatalk + if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then + { wget -qO- "${binaryURL}precompiled/netatalk224-${arch}_${debianName}.tgz" | sudo tar Pzx; } &> /dev/null + fi + sudo mandb &> /dev/null - [[ -f /usr/local/sbin/atalkd ]] && compileFromSource= + [[ -f /usr/local/sbin/atalkd ]] && compileFromSource= - break - done + break + done - if [[ $compileFromSource ]]; then - # Dependencies: build-deps for netatalk 2.2.4 - sudo apt-get -y install build-essential libssl-dev - if [[ $(apt-cache search '^libdb5.1-dev$') ]]; then # Wheezy - # Dependencies: build-deps for netatalk 2.2.4 - sudo apt-get -y install libdb5.1-dev - elif [[ $(apt-cache search '^libdb5.3-dev$') ]]; then # Jessie - # Dependencies: build-deps for netatalk 2.2.4 - sudo apt-get -y install libdb5.3-dev - else - echo "A2SERVER: WARNING: unknown version of libdb-dev is being installed." - # Dependencies: build-deps for netatalk 2.2.4 - sudo apt-get -y install libdb-dev - fi - if [[ $(apt-cache search '^libgcrypt11-dev$') ]]; then # Jessie or Wheezy - # Dependencies: build-deps for netatalk 2.2.4 - sudo apt-get -y install libgcrypt11-dev - else - echo "A2SERVER: WARNING: unknown version of libgcrypt-dev is being installed." - # Dependencies: build-deps for netatalk 2.2.4 - sudo apt-get -y install $(apt-cache search '^libgcrypt.*dev$' | sort -r | head -1 | cut -d ' ' -f 1) - fi - sudo apt-get clean + if [[ $compileFromSource ]]; then + # Dependencies: build-deps for netatalk 2.2.4 + sudo apt-get -y install build-essential libssl-dev + if [[ $(apt-cache search '^libdb5.1-dev$') ]]; then # Wheezy + # Dependencies: build-deps for netatalk 2.2.4 + sudo apt-get -y install libdb5.1-dev + elif [[ $(apt-cache search '^libdb5.3-dev$') ]]; then # Jessie + # Dependencies: build-deps for netatalk 2.2.4 + sudo apt-get -y install libdb5.3-dev + else + echo "A2SERVER: WARNING: unknown version of libdb-dev is being installed." + # Dependencies: build-deps for netatalk 2.2.4 + sudo apt-get -y install libdb-dev + fi + if [[ $(apt-cache search '^libgcrypt11-dev$') ]]; then # Jessie or Wheezy + # Dependencies: build-deps for netatalk 2.2.4 + sudo apt-get -y install libgcrypt11-dev + else + echo "A2SERVER: WARNING: unknown version of libgcrypt-dev is being installed." + # Dependencies: build-deps for netatalk 2.2.4 + sudo apt-get -y install $(apt-cache search '^libgcrypt.*dev$' | sort -r | head -1 | cut -d ' ' -f 1) + fi + sudo apt-get clean - # get Netatalk - rm -rf /tmp/netatalk &> /dev/null - mkdir /tmp/netatalk - cd /tmp/netatalk + # get Netatalk + rm -rf /tmp/netatalk &> /dev/null + mkdir /tmp/netatalk + cd /tmp/netatalk - if [[ $useExternalURL ]]; then - wget -qO netatalk-2.2.4.tar.gz "http://downloads.sourceforge.net/project/netatalk/netatalk/2.2.4/netatalk-2.2.4.tar.gz" - tar zxf netatalk-2.2.4.tar.gz &> /dev/null - fi - if [[ ! -d netatalk-2.2.4 ]]; then - wget -O netatalk-2.2.4.tar.gz "${binaryURL}external/source/netatalk-2.2.4.tar.gz" - tar zxf netatalk-2.2.4.tar.gz &> /dev/null - fi - cd netatalk-2.2.4 + if [[ $useExternalURL ]]; then + wget -qO netatalk-2.2.4.tar.gz "http://downloads.sourceforge.net/project/netatalk/netatalk/2.2.4/netatalk-2.2.4.tar.gz" + tar zxf netatalk-2.2.4.tar.gz &> /dev/null + fi + if [[ ! -d netatalk-2.2.4 ]]; then + wget -O netatalk-2.2.4.tar.gz "${binaryURL}external/source/netatalk-2.2.4.tar.gz" + tar zxf netatalk-2.2.4.tar.gz &> /dev/null + fi + cd netatalk-2.2.4 - # Patch the source so file dates are preserved during a GS/OS folder copy, - # and the AsanteTalk bridge consistently starts up in AppleTalk Phase 2 - # and the Dayna bridge doesn't crash GS/OS - # props to Steven Hirsch for these - sed -i ':a;N;$!ba;s/case FILPBIT_ATTR :\n *change_mdate = 1;\n/case FILPBIT_ATTR :\n/g' etc/afpd/file.c - sed -i 's/rtmp->rt_iface == iface/rtmp->rt_iface != iface/g' etc/atalkd/main.c + # Patch the source so file dates are preserved during a GS/OS folder copy, + # and the AsanteTalk bridge consistently starts up in AppleTalk Phase 2 + # and the Dayna bridge doesn't crash GS/OS + # props to Steven Hirsch for these + sed -i ':a;N;$!ba;s/case FILPBIT_ATTR :\n *change_mdate = 1;\n/case FILPBIT_ATTR :\n/g' etc/afpd/file.c + sed -i 's/rtmp->rt_iface == iface/rtmp->rt_iface != iface/g' etc/atalkd/main.c - # prepare to build Netatalk - ./configure --enable-debian --enable-ddp --enable-a2boot + # prepare to build Netatalk + ./configure --enable-debian --enable-ddp --enable-a2boot - # uninstall Netatalk if already installed - [[ -f /usr/local/sbin/afpd ]] && sudo make uninstall + # uninstall Netatalk if already installed + [[ -f /usr/local/sbin/afpd ]] && sudo make uninstall - # compile and install Netatalk - make - sudo make install + # compile and install Netatalk + make + sudo make install - # to remove the Netatalk source code (optional), type: - cd - rm -rf /tmp/netatalk - fi + # to remove the Netatalk source code (optional), type: + cd + rm -rf /tmp/netatalk + fi fi # --- Install MacIPgw if ! hash macipgw &> /dev/null; then - echo "A2SERVER: Installing TCP over AppleTalk (MacIP)..." + echo "A2SERVER: Installing TCP over AppleTalk (MacIP)..." - if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then - { wget -qO- "${binaryURL}precompiled/macipgw-${arch}.tgz" | sudo tar Pzx; } 2> /dev/null - fi + if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then + { wget -qO- "${binaryURL}precompiled/macipgw-${arch}.tgz" | sudo tar Pzx; } 2> /dev/null + fi - if ! hash macipgw &> /dev/null; then - wd="$PWD" - sudo apt-get -y install build-essential - rm -rf /tmp/macipgw &> /dev/null - mkdir /tmp/macipgw - cd /tmp/macipgw - if [[ $useExternalURL ]]; then - wget -qO macipgw.zip "https://github.com/zero2sixd/macipgw/archive/2a5f6a7521a627e46b18468d44f4306fb0a7b7ab.zip" - unzip macipgw.zip 2> /dev/null - rm macipgw.zip &> /dev/null - fi - if [[ ! -d macipgw-master ]]; then - wget -qO macipgw.zip "${binaryURL}external/source/macipgw.zip" - unzip macipgw.zip 2> /dev/null - rm macipgw.zip &> /dev/null - fi - cd macipgw* - make - sudo make install - cd "$wd" - rm -rf /tmp/macipgw - fi + if ! hash macipgw &> /dev/null; then + wd="$PWD" + sudo apt-get -y install build-essential + rm -rf /tmp/macipgw &> /dev/null + mkdir /tmp/macipgw + cd /tmp/macipgw + if [[ $useExternalURL ]]; then + wget -qO macipgw.zip "https://github.com/zero2sixd/macipgw/archive/2a5f6a7521a627e46b18468d44f4306fb0a7b7ab.zip" + unzip macipgw.zip 2> /dev/null + rm macipgw.zip &> /dev/null + fi + if [[ ! -d macipgw-master ]]; then + wget -qO macipgw.zip "${binaryURL}external/source/macipgw.zip" + unzip macipgw.zip 2> /dev/null + rm macipgw.zip &> /dev/null + fi + cd macipgw* + make + sudo make install + cd "$wd" + rm -rf /tmp/macipgw + fi else - echo "A2SERVER: TCP over AppleTalk (MacIP) has already been installed." + echo "A2SERVER: TCP over AppleTalk (MacIP) has already been installed." fi # --- Configuring Netatalk @@ -236,8 +236,8 @@ echo "A2SERVER: Configuring Netatalk..." # if missing Netatalk startup file, download a fresh one if [ ! -f /etc/init.d/netatalk ]; then - echo "A2SERVER: Downloading new Netatalk startup script..." - sudo wget -qO /etc/init.d/netatalk ${binaryURL}netatalk-init.d-clean.txt + echo "A2SERVER: Downloading new Netatalk startup script..." + sudo wget -qO /etc/init.d/netatalk ${binaryURL}netatalk-init.d-clean.txt fi # make the Netatalk startup script work correctly @@ -247,7 +247,7 @@ sudo sed -i 's/bin\/sh/bin\/bash/' /etc/init.d/netatalk sudo sed -i 's/#ATALKD_RUN=no/ATALKD_RUN=yes/' /etc/default/netatalk sudo sed -i 's/#ATALK_BGROUND=no/ATALK_BGROUND=yes/' /etc/default/netatalk if [[ ! $(grep 'kernelRelease' /etc/init.d/netatalk) ]]; then - sudo sed -i 's@\(\tif \[ x\"$ATALKD_RUN\)@\n\t# check for valid AppleTalk kernel module\n\t[[ $ATALKD_RUN == "yes" ]] \&\& { kernelRelease=$(uname -r); kernelMajor=$(cut -d "." -f 1 <<< $kernelRelease); kernelMinor=$(cut -d "." -f 2 <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); kernelPatch=$(cut -d "." -f 3- <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); [[ ( $kernelMajor -eq 3 \&\& $kernelMinor -ge 12 \&\& $kernelMinor -le 15 ) \&\& ( ! ( -f /usr/bin/raspi-config \&\& $kernelMinor -eq 12 \&\& $kernelPatch -ge 25 ) ) \&\& ( ( ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ) || $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d " ") != "ecb239fc084c36de93f6926e7749b80f6024f269" ) ]] \&\& { ATALKD_RUN=no; echo "[AppleTalk networking is not available.]" 1>\&2; } }\n\n\1@' /etc/init.d/netatalk + sudo sed -i 's@\(\tif \[ x\"$ATALKD_RUN\)@\n\t# check for valid AppleTalk kernel module\n\t[[ $ATALKD_RUN == "yes" ]] \&\& { kernelRelease=$(uname -r); kernelMajor=$(cut -d "." -f 1 <<< $kernelRelease); kernelMinor=$(cut -d "." -f 2 <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); kernelPatch=$(cut -d "." -f 3- <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); [[ ( $kernelMajor -eq 3 \&\& $kernelMinor -ge 12 \&\& $kernelMinor -le 15 ) \&\& ( ! ( -f /usr/bin/raspi-config \&\& $kernelMinor -eq 12 \&\& $kernelPatch -ge 25 ) ) \&\& ( ( ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ) || $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d " ") != "ecb239fc084c36de93f6926e7749b80f6024f269" ) ]] \&\& { ATALKD_RUN=no; echo "[AppleTalk networking is not available.]" 1>\&2; } }\n\n\1@' /etc/init.d/netatalk fi sudo sed -i 's/Starting Netatalk services (this will take a while): /Starting Netatalk services"\n\t\t\t[[ $ATALKD_RUN == "yes" ]] \&\& echo -n " (this will take 45 seconds)"\n\t\t\techo -n ":/' /etc/init.d/netatalk sudo sed -i 's/Starting Netatalk services in the background./Netatalk services will be available in 45 seconds./' /etc/init.d/netatalk @@ -255,8 +255,8 @@ sudo sed -i 's/-n "Restarting Netatalk Daemons (this will take a while)"/"Restar # enable MacIPgw support after launching atalkd if ! grep -q -i 'macipgw' /etc/init.d/netatalk; then - sudo sed -i ':a;N;$!ba;s@\(echo -n " atalkd"\)\(.*# prepare\)@\1\n\n\t\t# start MacIPgw (TCP over AppleTalk) service\n\t\tps aux | grep -q "[m]acipgw" \&\& sudo killall macipgw 2> /dev/null || :\n\t\tatalkd_interface=$(grep "^[^ #]" /etc/netatalk/atalkd.conf | tail -1 | cut -d " " -f 1)\n\t\tsysctl -w net.ipv4.ip_forward=1 > /dev/null\n\t\tmacipgw -n 8.8.8.8 192.168.151.0 255.255.255.0\n\t\t/sbin/iptables -t nat -A POSTROUTING -o ${atalkd_interface} -j MASQUERADE\n\t\t/sbin/iptables -A FORWARD -i ${atalkd_interface} -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT\n\t\t/sbin/iptables -A FORWARD -i tun1 -o ${atalkd_interface} -j ACCEPT\n\n\t\techo -n " macipgw"\n\2@' /etc/init.d/netatalk - sudo sed -i 's@\(start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/atalkd.*$\)@\1\n echo -n " macipgw"\n sudo killall macipgw 2> /dev/null@' /etc/init.d/netatalk + sudo sed -i ':a;N;$!ba;s@\(echo -n " atalkd"\)\(.*# prepare\)@\1\n\n\t\t# start MacIPgw (TCP over AppleTalk) service\n\t\tps aux | grep -q "[m]acipgw" \&\& sudo killall macipgw 2> /dev/null || :\n\t\tatalkd_interface=$(grep "^[^ #]" /etc/netatalk/atalkd.conf | tail -1 | cut -d " " -f 1)\n\t\tsysctl -w net.ipv4.ip_forward=1 > /dev/null\n\t\tmacipgw -n 8.8.8.8 192.168.151.0 255.255.255.0\n\t\t/sbin/iptables -t nat -A POSTROUTING -o ${atalkd_interface} -j MASQUERADE\n\t\t/sbin/iptables -A FORWARD -i ${atalkd_interface} -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT\n\t\t/sbin/iptables -A FORWARD -i tun1 -o ${atalkd_interface} -j ACCEPT\n\n\t\techo -n " macipgw"\n\2@' /etc/init.d/netatalk + sudo sed -i 's@\(start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/atalkd.*$\)@\1\n echo -n " macipgw"\n sudo killall macipgw 2> /dev/null@' /etc/init.d/netatalk fi # enable network boot support in netatalk @@ -277,14 +277,14 @@ sudo sed -i "s/#AFPD_GUEST=nobody/AFPD_GUEST=$USER/" /etc/default/netatalk [[ -L /etc/netatalk ]] || sudo ln -s /usr/local/etc/netatalk /etc/netatalk if [[ ! $(grep '^- -ddp.*uams_randnum.so' /usr/local/etc/netatalk/afpd.conf) ]]; then - # set up to allow Guest, Cleartext, RandNum, DHX, and DHX2 login - # disable DHX (DHCAST128) on Raspberry Pi, which refuses uams if the config string is too long - [[ -f /usr/bin/raspi-config ]] && dhx="" || dhx="uams_dhx.so," - echo -n -e \ - "- -ddp -tcp -uamlist uams_guest.so,uams_clrtxt.so,uams_randnum.so" \ - | sudo tee -a /usr/local/etc/netatalk/afpd.conf > /dev/null - echo -e ",${dhx}uams_dhx2.so" \ - | sudo tee -a /usr/local/etc/netatalk/afpd.conf > /dev/null + # set up to allow Guest, Cleartext, RandNum, DHX, and DHX2 login + # disable DHX (DHCAST128) on Raspberry Pi, which refuses uams if the config string is too long + [[ -f /usr/bin/raspi-config ]] && dhx="" || dhx="uams_dhx.so," + echo -n -e \ + "- -ddp -tcp -uamlist uams_guest.so,uams_clrtxt.so,uams_randnum.so" \ + | sudo tee -a /usr/local/etc/netatalk/afpd.conf > /dev/null + echo -e ",${dhx}uams_dhx2.so" \ + | sudo tee -a /usr/local/etc/netatalk/afpd.conf > /dev/null fi # replace home folder share and end of file mark with share placeholders @@ -297,30 +297,30 @@ sudo sed -i 's/^:DEFAULT/#:DEFAULT/' \ # if [[ ! $(grep ^eth0 /usr/local/etc/netatalk/atalkd.conf) && ! $(grep ^wlan0 /usr/local/etc/netatalk/atalkd.conf) ]]; then if [[ $(tac /usr/local/etc/netatalk/atalkd.conf | sed '/./,$!d' | head -1 | cut -c 1) == "#" ]]; then - # enable netatalk on the default network interface - # needs -router and -zone to prevent GS/OS AppleShare CDEV crash when used - # with Dayna or Asante bridges - echo -e 'eth0 -router -phase 2 -net 1 -zone "A2SERVER"' | sudo tee -a /usr/local/etc/netatalk/atalkd.conf > /dev/null + # enable netatalk on the default network interface + # needs -router and -zone to prevent GS/OS AppleShare CDEV crash when used + # with Dayna or Asante bridges + echo -e 'eth0 -router -phase 2 -net 1 -zone "A2SERVER"' | sudo tee -a /usr/local/etc/netatalk/atalkd.conf > /dev/null fi # Raspberry Pi if [[ $isRpi ]]; then - # blink LED upon netatalk startup - if [[ ! $(grep 'led0' /etc/init.d/netatalk) ]]; then - sudo sed -i ':a;N;$!ba;s/fi\n}/fi\n\n # blink LED on Raspberry Pi\n ([[ -e \/sys\/class\/leds\/ACT ]] \&\& led=ACT || led=led0; echo none > \/sys\/class\/leds\/$led\/trigger; for i in {1..20}; do echo 1 > \/sys\/class\/leds\/$led\/brightness; sleep 0.25; echo 0 > \/sys\/class\/leds\/$led\/brightness; sleep 0.25; done; echo mmc0 > \/sys\/class\/leds\/$led\/trigger) \&\n}/' /etc/init.d/netatalk - fi + # blink LED upon netatalk startup + if [[ ! $(grep 'led0' /etc/init.d/netatalk) ]]; then + sudo sed -i ':a;N;$!ba;s/fi\n}/fi\n\n # blink LED on Raspberry Pi\n ([[ -e \/sys\/class\/leds\/ACT ]] \&\& led=ACT || led=led0; echo none > \/sys\/class\/leds\/$led\/trigger; for i in {1..20}; do echo 1 > \/sys\/class\/leds\/$led\/brightness; sleep 0.25; echo 0 > \/sys\/class\/leds\/$led\/brightness; sleep 0.25; done; echo mmc0 > \/sys\/class\/leds\/$led\/trigger) \&\n}/' /etc/init.d/netatalk + fi fi # 1.3.0: we are no longer setting up new GSFILES # set up GSFILES share (for GS data files, not GSOS system) # classic Mac OS file names are allowed (31 chars, mixed case, everything but colons) #sudo sed -i \ -# 's/^#share1/\/media\/A2SHARED\/GSFILES\ GSFILES ea:ad/' \ -# /usr/local/etc/netatalk/AppleVolumes.default +# 's/^#share1/\/media\/A2SHARED\/GSFILES\ GSFILES ea:ad/' \ +# /usr/local/etc/netatalk/AppleVolumes.default # 1.3.0: if GSFILES is being shared, make directory if not there if grep -q '^/srv/A2SERVER/GSFILES' /usr/local/etc/netatalk/AppleVolumes.default; then - [[ -d /srv/A2SERVER/GSFILES ]] || mkdir -p /srv/A2SERVER/GSFILES; + [[ -d /srv/A2SERVER/GSFILES ]] || mkdir -p /srv/A2SERVER/GSFILES; fi # prior to 1.3.0: @@ -333,130 +333,130 @@ fi # restore known GS/OS file paths to mixed case # set up ciopfs (case insensitive file system) for share if [[ -d /srv/A2SERVER/A2FILES && ! -d /srv/A2SERVER/.a2files ]]; then - echo "A2SERVER: Converting A2FILES to support mixed case..." - sudo /etc/init.d/netatalk stop &> /dev/null - sudo /etc/init.d/samba stop &> /dev/null - if ! hash getfattr &> /dev/null; then - # Dependency: for ciopfs conversion (setfattr) - sudo apt-get -y install attr &> /dev/null - sudo apt-get clean - fi - rm /srv/A2SERVER/A2FILES/.APPLEDESKTOP 2> /dev/null - mkdir -p /tmp/netboot - wget -qO /tmp/A2FILES-list.txt ${binaryURL}A2FILES-list.txt - find /srv/A2SERVER/A2FILES -name '*' | tail -n +2 | tac > /tmp/filelist.txt - while read thisFile; do - mixedCase="${thisFile##*/}" - gsosPath=$(grep -i -m 1 "^${thisFile}$" /tmp/A2FILES-list.txt) - [[ $gsosPath ]] && mixedCase="${gsosPath##*/}" - sudo setfattr -n "user.filename" -v "$mixedCase" "$thisFile" - if [[ ${thisFile##*/} != $mixedCase ]]; then - echo -e " renaming $thisFile to ${mixedCase}\n" - else - echo -e " processing $thisFile\n" - fi - sudo mv "$thisFile" "${thisFile%/*}/${mixedCase,,}" 2> /dev/null - done < /tmp/filelist.txt - mv /srv/A2SERVER/A2FILES /srv/A2SERVER/.a2files - mkdir /srv/A2SERVER/A2FILES - sudo sed -i 's/casefold:toupper //' /usr/local/etc/netatalk/AppleVolumes.default 2> /dev/null - sudo sed -i 's/^VOLCASEFOLD:.*/VOLCASEFOLD:/' /srv/A2SERVER/.a2files/.appledesktop/.volinfo 2> /dev/null - sudo sed -i 's|/media/A2SHARED/A2FILES|/srv/A2SERVER/A2FILES|' /srv/A2SERVER/.a2files/.appledesktop/.volinfo 2> /dev/null + echo "A2SERVER: Converting A2FILES to support mixed case..." + sudo /etc/init.d/netatalk stop &> /dev/null + sudo /etc/init.d/samba stop &> /dev/null + if ! hash getfattr &> /dev/null; then + # Dependency: for ciopfs conversion (setfattr) + sudo apt-get -y install attr &> /dev/null + sudo apt-get clean + fi + rm /srv/A2SERVER/A2FILES/.APPLEDESKTOP 2> /dev/null + mkdir -p /tmp/netboot + wget -qO /tmp/A2FILES-list.txt ${binaryURL}A2FILES-list.txt + find /srv/A2SERVER/A2FILES -name '*' | tail -n +2 | tac > /tmp/filelist.txt + while read thisFile; do + mixedCase="${thisFile##*/}" + gsosPath=$(grep -i -m 1 "^${thisFile}$" /tmp/A2FILES-list.txt) + [[ $gsosPath ]] && mixedCase="${gsosPath##*/}" + sudo setfattr -n "user.filename" -v "$mixedCase" "$thisFile" + if [[ ${thisFile##*/} != $mixedCase ]]; then + echo -e " renaming $thisFile to ${mixedCase}\n" + else + echo -e " processing $thisFile\n" + fi + sudo mv "$thisFile" "${thisFile%/*}/${mixedCase,,}" 2> /dev/null + done < /tmp/filelist.txt + mv /srv/A2SERVER/A2FILES /srv/A2SERVER/.a2files + mkdir /srv/A2SERVER/A2FILES + sudo sed -i 's/casefold:toupper //' /usr/local/etc/netatalk/AppleVolumes.default 2> /dev/null + sudo sed -i 's/^VOLCASEFOLD:.*/VOLCASEFOLD:/' /srv/A2SERVER/.a2files/.appledesktop/.volinfo 2> /dev/null + sudo sed -i 's|/media/A2SHARED/A2FILES|/srv/A2SERVER/A2FILES|' /srv/A2SERVER/.a2files/.appledesktop/.volinfo 2> /dev/null fi # 1.3.0: remove GSFILES if empty if grep -q '^/srv/A2SERVER/GSFILES' /usr/local/etc/netatalk/AppleVolumes.default; then - gsFilesContents= - if [[ -d /srv/A2SERVER/GSFILES ]]; then - gsFilesContents="$(find /srv/A2SERVER/GSFILES -not -path '*/\.*' | grep -v '^/srv/A2SERVER/GSFILES$' | grep -v '^/srv/A2SERVER/GSFILES/Network Trash Folder$' | grep -v '^/srv/A2SERVER/GSFILES/Temporary Items$')" - if [[ ! $gsFilesContents ]]; then - echo "A2SERVER: Removing empty GSFILES shared volume..." - sudo /etc/init.d/netatalk stop &> /dev/null - sudo /etc/init.d/samba stop &> /dev/null - sudo sed -i 's|^/srv/A2SERVER/GSFILES.*$|#share1|' /usr/local/etc/netatalk/AppleVolumes.default - sudo rm -r /srv/A2SERVER/GSFILES - else - echo "A2SERVER: GSFILES shared volume has files, leaving as is." - fi - fi + gsFilesContents= + if [[ -d /srv/A2SERVER/GSFILES ]]; then + gsFilesContents="$(find /srv/A2SERVER/GSFILES -not -path '*/\.*' | grep -v '^/srv/A2SERVER/GSFILES$' | grep -v '^/srv/A2SERVER/GSFILES/Network Trash Folder$' | grep -v '^/srv/A2SERVER/GSFILES/Temporary Items$')" + if [[ ! $gsFilesContents ]]; then + echo "A2SERVER: Removing empty GSFILES shared volume..." + sudo /etc/init.d/netatalk stop &> /dev/null + sudo /etc/init.d/samba stop &> /dev/null + sudo sed -i 's|^/srv/A2SERVER/GSFILES.*$|#share1|' /usr/local/etc/netatalk/AppleVolumes.default + sudo rm -r /srv/A2SERVER/GSFILES + else + echo "A2SERVER: GSFILES shared volume has files, leaving as is." + fi + fi fi # set up A2FILES case-insensitive share (for ProDOS 8 files, and GS/OS system) sudo sed -i \ - 's/^#share2/\/srv\/A2SERVER\/A2FILES\ A2FILES options:prodos\ ea:ad/' \ - /usr/local/etc/netatalk/AppleVolumes.default + 's/^#share2/\/srv\/A2SERVER\/A2FILES\ A2FILES options:prodos\ ea:ad/' \ + /usr/local/etc/netatalk/AppleVolumes.default [[ -d /srv/A2SERVER/A2FILES ]] || mkdir -p /srv/A2SERVER/A2FILES [[ -d /srv/A2SERVER/.a2files ]] || mkdir -p /srv/A2SERVER/.a2files # set up ciopfs if ! hash ciopfs &> /dev/null; then - echo "A2SERVER: Installing ciopfs (case insensitive file system)..." - cd /tmp + echo "A2SERVER: Installing ciopfs (case insensitive file system)..." + cd /tmp - # Dependency: For ciopfs - sudo apt-get -y install fuse libglib2.0-0 libattr1 libfuse2 - if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then - { wget -qO- "${binaryURL}precompiled/ciopfs-${arch}.tgz" | sudo tar Pzx; } &> /dev/null - fi - if [[ -f /etc/fuse.conf ]] && sudo grep -q user_allow_other /etc/fuse.conf; then - sudo sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf - else - echo "user_allow_other" | sudo tee /etc/fuse.conf > /dev/null - fi + # Dependency: For ciopfs + sudo apt-get -y install fuse libglib2.0-0 libattr1 libfuse2 + if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then + { wget -qO- "${binaryURL}precompiled/ciopfs-${arch}.tgz" | sudo tar Pzx; } &> /dev/null + fi + if [[ -f /etc/fuse.conf ]] && sudo grep -q user_allow_other /etc/fuse.conf; then + sudo sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf + else + echo "user_allow_other" | sudo tee /etc/fuse.conf > /dev/null + fi - if ! hash ciopfs &> /dev/null; then - if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then - # prepare for installing packages - sudo apt-get -y update - touch /tmp/a2server-packageReposUpdated - fi + if ! hash ciopfs &> /dev/null; then + if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then + # prepare for installing packages + sudo apt-get -y update + touch /tmp/a2server-packageReposUpdated + fi - # Dependency: build-dep for ciopfs - sudo apt-get -y install build-essential libfuse-dev libglib2.0-dev libattr1-dev - sudo apt-get -y clean + # Dependency: build-dep for ciopfs + sudo apt-get -y install build-essential libfuse-dev libglib2.0-dev libattr1-dev + sudo apt-get -y clean - cd /tmp - rm -rf /tmp/ciopfs &> /dev/null - mkdir /tmp/ciopfs - cd /tmp/ciopfs - if [[ $useExternalURL ]]; then - wget -q -O ciopfs-0.4.tar.gz http://www.brain-dump.org/projects/ciopfs/ciopfs-0.4.tar.gz - tar zxf ciopfs-0.4.tar.gz &> /dev/null - fi - if [ ! -f ciopfs*/ciopfs.c ]; then # single brackets required for glob - wget -q -O ciopfs-0.4.tar.gz ${binaryURL}external/source/ciopfs-0.4.tar.gz - tar zxf ciopfs-0.4.tar.gz &> /dev/null - fi - cd ciopfs* - make - sudo mv ciopfs /usr/local/bin - cd - rm -rf /tmp/ciopfs - fi - if ! grep -q '^ciopfs' /etc/fstab; then - echo "ciopfs#/srv/A2SERVER/.a2files /srv/A2SERVER/A2FILES fuse allow_other 0 0" | sudo tee -a /etc/fstab > /dev/null - fi - if ! mount | grep '^ciopfs.*A2FILES'; then - sudo ciopfs /srv/A2SERVER/.a2files /srv/A2SERVER/A2FILES -o allow_other - fi + cd /tmp + rm -rf /tmp/ciopfs &> /dev/null + mkdir /tmp/ciopfs + cd /tmp/ciopfs + if [[ $useExternalURL ]]; then + wget -q -O ciopfs-0.4.tar.gz http://www.brain-dump.org/projects/ciopfs/ciopfs-0.4.tar.gz + tar zxf ciopfs-0.4.tar.gz &> /dev/null + fi + if [ ! -f ciopfs*/ciopfs.c ]; then # single brackets required for glob + wget -q -O ciopfs-0.4.tar.gz ${binaryURL}external/source/ciopfs-0.4.tar.gz + tar zxf ciopfs-0.4.tar.gz &> /dev/null + fi + cd ciopfs* + make + sudo mv ciopfs /usr/local/bin + cd + rm -rf /tmp/ciopfs + fi + if ! grep -q '^ciopfs' /etc/fstab; then + echo "ciopfs#/srv/A2SERVER/.a2files /srv/A2SERVER/A2FILES fuse allow_other 0 0" | sudo tee -a /etc/fstab > /dev/null + fi + if ! mount | grep '^ciopfs.*A2FILES'; then + sudo ciopfs /srv/A2SERVER/.a2files /srv/A2SERVER/A2FILES -o allow_other + fi else - echo "A2SERVER: ciopfs (case insensitive file system) has already been installed." + echo "A2SERVER: ciopfs (case insensitive file system) has already been installed." fi if [[ ! -d /srv/A2SERVER/A2FILES/.AppleDesktop ]]; then - cd /srv/A2SERVER/A2FILES - mkdir .AppleDesktop + cd /srv/A2SERVER/A2FILES + mkdir .AppleDesktop fi # set up ADTDISKS share (ADTPro disk image folder, if A2CLOUD is installed) # classic Mac OS file names are allowed (31 chars, mixed case, everything but colons) if [[ -d /usr/local/adtpro/disks ]]; then # A2CLOUD/ADTPro installed - if [[ ! -d /srv/A2SERVER/ADTDISKS ]]; then - ln -s /usr/local/adtpro/disks /srv/A2SERVER/ADTDISKS - fi - if [[ ! $(grep ADTDISKS /usr/local/etc/netatalk/AppleVolumes.default) ]]; then - sudo sed -i 's@^# End of File@/srv/A2SERVER/ADTDISKS ADTDISKS ea:ad\n\n# End of File@' /usr/local/etc/netatalk/AppleVolumes.default - fi + if [[ ! -d /srv/A2SERVER/ADTDISKS ]]; then + ln -s /usr/local/adtpro/disks /srv/A2SERVER/ADTDISKS + fi + if [[ ! $(grep ADTDISKS /usr/local/etc/netatalk/AppleVolumes.default) ]]; then + sudo sed -i 's@^# End of File@/srv/A2SERVER/ADTDISKS ADTDISKS ea:ad\n\n# End of File@' /usr/local/etc/netatalk/AppleVolumes.default + fi fi # to make Netatalk start up when the server boots: @@ -472,19 +472,19 @@ afpsync -v < /dev/null # skip if we've already done this if [[ -f /usr/local/etc/netatalk/afppasswd ]]; then - echo "A2SERVER: Netatalk user logins have already been set up." + echo "A2SERVER: Netatalk user logins have already been set up." else - echo - echo "A2SERVER: Setting up AFP password 'apple2' for Apple II and Mac clients..." - # echo "A2SERVER: Enter 'apple2' or another password of up to eight characters." - echo - # set registered user login using RandNum authentication - sudo afppasswd -c - sudo sed -i "s/^\(${USER}\).*$/\1:6170706C65320000:****************:********/" /usr/local/etc/netatalk/afppasswd - # (The afppasswd -c only needs to ever be done once. You can repeat - # the afppasswd -a to make Netatalk randnum logins for other Linux users.) + echo + echo "A2SERVER: Setting up AFP password 'apple2' for Apple II and Mac clients..." + # echo "A2SERVER: Enter 'apple2' or another password of up to eight characters." + echo + # set registered user login using RandNum authentication + sudo afppasswd -c + sudo sed -i "s/^\(${USER}\).*$/\1:6170706C65320000:****************:********/" /usr/local/etc/netatalk/afppasswd + # (The afppasswd -c only needs to ever be done once. You can repeat + # the afppasswd -a to make Netatalk randnum logins for other Linux users.) fi @@ -499,123 +499,123 @@ kernelMajorMinor=$(cut -d '.' -f 1-2 <<< $kernelRelease) # if on kernel 3.12 through 3.15, check if we need to delete AppleTalk module to prevent kernel panics if [[ $kernelMajor -eq 3 && $kernelMinor -ge 12 && $kernelMinor -le 15 ]]; then - # if not RPi, or RPi without ivanx-fixed AppleTalk module, delete the module - if [[ ! ( $isRpi && $kernelMinor -eq 12 && $kernelPatch -ge 25 ) ]]; then - if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then - if [[ $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then - # stop Netatalk - sudo /etc/init.d/netatalk stop &> /dev/null - echo "A2SERVER: Deleting defective AppleTalk kernel module..." - sudo rmmod appletalk 2> /dev/null - sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk - # disable single-user mode on Pi (other Linux can use Recovery boot) - if [[ $isRpi && $(grep ' single' /boot/cmdline.txt 2> /dev/null) ]]; then - echo "A2SERVER: Disabling single-user mode for next boot..." - sudo sed -i 's/ single//' /boot/cmdline.txt - touch /tmp/singleUser # so note to restart can display following install - fi - fi - fi - fi + # if not RPi, or RPi without ivanx-fixed AppleTalk module, delete the module + if [[ ! ( $isRpi && $kernelMinor -eq 12 && $kernelPatch -ge 25 ) ]]; then + if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then + if [[ $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then + # stop Netatalk + sudo /etc/init.d/netatalk stop &> /dev/null + echo "A2SERVER: Deleting defective AppleTalk kernel module..." + sudo rmmod appletalk 2> /dev/null + sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk + # disable single-user mode on Pi (other Linux can use Recovery boot) + if [[ $isRpi && $(grep ' single' /boot/cmdline.txt 2> /dev/null) ]]; then + echo "A2SERVER: Disabling single-user mode for next boot..." + sudo sed -i 's/ single//' /boot/cmdline.txt + touch /tmp/singleUser # so note to restart can display following install + fi + fi + fi + fi fi # if IPDDP module exists (e.g. Debian, but not Raspbian), -# AppleTalk kernel module has been compiled to support it and can't work with MacIP +# AppleTalk kernel module has been compiled to support it and can't work with MacIP if [[ -f "/lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko" ]]; then - sudo /etc/init.d/netatalk stop &> /dev/null - sudo rmmod ipddp 2> /dev/null - sudo rmmod appletalk 2> /dev/null - echo "A2SERVER: Replacing AppleTalk kernel module (IPDDP disabled) for MacIP use..." + sudo /etc/init.d/netatalk stop &> /dev/null + sudo rmmod ipddp 2> /dev/null + sudo rmmod appletalk 2> /dev/null + echo "A2SERVER: Replacing AppleTalk kernel module (IPDDP disabled) for MacIP use..." - sudo mv /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko /tmp 2> /dev/null + sudo mv /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko /tmp 2> /dev/null - if [[ ${arch%_*} == "debian" ]]; then - echo "A2SERVER: Fetching AppleTalk kernel module for Debian..." - wget -qO /tmp/appletalk.tgz ${binaryURL}precompiled/appletalk-$kernelRelease-${arch}.tgz - if [[ $? -eq 0 ]]; then - # if we found a prebuilt one on a2server site, install it and load it - sudo tar Pxf /tmp/appletalk.tgz &> /dev/null - sudo depmod - sudo modprobe appletalk - if [[ $(lsmod | grep appletalk) ]]; then - # if it loaded, restart netatalk - sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk - sudo /etc/init.d/netatalk restart &> /dev/null - else - # if we didn't load it successfully, remove it - sudo rm /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko 2> /dev/null - fi - fi - fi + if [[ ${arch%_*} == "debian" ]]; then + echo "A2SERVER: Fetching AppleTalk kernel module for Debian..." + wget -qO /tmp/appletalk.tgz ${binaryURL}precompiled/appletalk-$kernelRelease-${arch}.tgz + if [[ $? -eq 0 ]]; then + # if we found a prebuilt one on a2server site, install it and load it + sudo tar Pxf /tmp/appletalk.tgz &> /dev/null + sudo depmod + sudo modprobe appletalk + if [[ $(lsmod | grep appletalk) ]]; then + # if it loaded, restart netatalk + sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk + sudo /etc/init.d/netatalk restart &> /dev/null + else + # if we didn't load it successfully, remove it + sudo rm /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko 2> /dev/null + fi + fi + fi - if ! lsmod | grep -q appletalk; then - # we don't have a prebuilt AppleTalk module, try to build from source - if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then - # prepare for installing packages - sudo apt-get -y update - touch /tmp/a2server-packageReposUpdated - fi + if ! lsmod | grep -q appletalk; then + # we don't have a prebuilt AppleTalk module, try to build from source + if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then + # prepare for installing packages + sudo apt-get -y update + touch /tmp/a2server-packageReposUpdated + fi - # kernel module compile adapted from from: http://askubuntu.com/a/338403/288003 - for i in 1; do - echo "A2SERVER: Building AppleTalk kernel module..." - [[ -f /boot/config-$kernelRelease ]] || break - sudo apt-get -y install linux-headers-$kernelRelease linux-source-$kernelMajorMinor || break - sudo apt-get -y install build-essential - cd /usr/src - kernelSrc=$(find linux-source-${kernelMajorMinor}*) - if [[ ${kernelSrc##*.} == "xz" ]]; then - { xzcat $kernelSrc | sudo tar x; } &> /dev/null - elif [[ ${kernelSrc##*.} == "bz2" ]]; then - sudo tar jxf $kernelSrc &> /dev/null - elif [[ ${kernelSrc##*.} == "gz" || ${kernelSrc##*.} == "tgz" ]]; then - sudo tar zxf $kernelSrc &> /dev/null - fi - cd linux-source-$kernelMajorMinor - sudo make mrproper - sudo cp ../linux-headers-$kernelRelease/Module.symvers . - yes '' | sudo make oldconfig - sudo sed -i 's:^.*IPDDP.*$:# CONFIG_IPDDP is not set:gI' .config # disable IPDDP in kernel config - sudo sed -i '$!N; /^\(# CONFIG_IPDDP is not set\)\n\1$/!P; D' .config # delete repeated entries - sudo make prepare - sudo make modules_prepare - sudo make SUBDIRS=scripts/mod - sudo make SUBDIRS=net/appletalk modules - sudo cp net/appletalk/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk - sudo depmod - sudo modprobe appletalk - sudo rm -r /lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko - sudo rmdir /lib/modules/$kernelRelease/kernel/drivers/net/appletalk 2> /dev/null + # kernel module compile adapted from from: http://askubuntu.com/a/338403/288003 + for i in 1; do + echo "A2SERVER: Building AppleTalk kernel module..." + [[ -f /boot/config-$kernelRelease ]] || break + sudo apt-get -y install linux-headers-$kernelRelease linux-source-$kernelMajorMinor || break + sudo apt-get -y install build-essential + cd /usr/src + kernelSrc=$(find linux-source-${kernelMajorMinor}*) + if [[ ${kernelSrc##*.} == "xz" ]]; then + { xzcat $kernelSrc | sudo tar x; } &> /dev/null + elif [[ ${kernelSrc##*.} == "bz2" ]]; then + sudo tar jxf $kernelSrc &> /dev/null + elif [[ ${kernelSrc##*.} == "gz" || ${kernelSrc##*.} == "tgz" ]]; then + sudo tar zxf $kernelSrc &> /dev/null + fi + cd linux-source-$kernelMajorMinor + sudo make mrproper + sudo cp ../linux-headers-$kernelRelease/Module.symvers . + yes '' | sudo make oldconfig + sudo sed -i 's:^.*IPDDP.*$:# CONFIG_IPDDP is not set:gI' .config # disable IPDDP in kernel config + sudo sed -i '$!N; /^\(# CONFIG_IPDDP is not set\)\n\1$/!P; D' .config # delete repeated entries + sudo make prepare + sudo make modules_prepare + sudo make SUBDIRS=scripts/mod + sudo make SUBDIRS=net/appletalk modules + sudo cp net/appletalk/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk + sudo depmod + sudo modprobe appletalk + sudo rm -r /lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko + sudo rmdir /lib/modules/$kernelRelease/kernel/drivers/net/appletalk 2> /dev/null - # clean up - cd - sudo rm /usr/src/$kernelSrc - sudo rm -r /usr/src/linux-source-$kernelMajorMinor - sudo apt-get -y purge linux-source-$kernelMajorMinor - done - fi + # clean up + cd + sudo rm /usr/src/$kernelSrc + sudo rm -r /usr/src/linux-source-$kernelMajorMinor + sudo apt-get -y purge linux-source-$kernelMajorMinor + done + fi - if [[ $(lsmod | grep appletalk) ]]; then - # if it loaded, make permanent and restart netatalk - sudo rm /lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko 2> /dev/null - sudo sed -i 's:^.*IPDDP.*$:# CONFIG_IPDDP is not set:gI' /boot/config-$kernelRelease - sudo sed -i '$!N; /^\(# CONFIG_IPDDP is not set\)\n\1$/!P; D' /boot/config-$kernelRelease - sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart &> /dev/null - else - # if we didn't load it successfully, put back the one that was there - echo "A2SERVER: Unable to replace AppleTalk module, replacing original." - sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null - sudo depmod - touch /tmp/noMacIP # to notify at end of install - fi + if [[ $(lsmod | grep appletalk) ]]; then + # if it loaded, make permanent and restart netatalk + sudo rm /lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko 2> /dev/null + sudo sed -i 's:^.*IPDDP.*$:# CONFIG_IPDDP is not set:gI' /boot/config-$kernelRelease + sudo sed -i '$!N; /^\(# CONFIG_IPDDP is not set\)\n\1$/!P; D' /boot/config-$kernelRelease + sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart &> /dev/null + else + # if we didn't load it successfully, put back the one that was there + echo "A2SERVER: Unable to replace AppleTalk module, replacing original." + sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null + sudo depmod + touch /tmp/noMacIP # to notify at end of install + fi fi # --- Start Netatalk (if not running) bground= if [[ $(grep 'ATALK_BGROUND=yes' /etc/default/netatalk) ]]; then - bground=1 - sudo sed -i 's/ATALK_BGROUND=yes/ATALK_BGROUND=no/' /etc/default/netatalk + bground=1 + sudo sed -i 's/ATALK_BGROUND=yes/ATALK_BGROUND=no/' /etc/default/netatalk fi [[ $(ps --no-headers -C afpd) ]] || sudo /etc/init.d/netatalk start 2> /dev/null @@ -627,93 +627,93 @@ echo # if atalkd isn't running (no AppleTalk), and this is a Rasbperry Pi: if [[ ( ! $(ps aux | grep [a]talkd) ) && ( $isRpi ) ]]; then - # if AppleTalk module exists, try to load it - if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # module present, but not loaded? - sudo depmod - sudo modprobe appletalk - if [[ $(lsmod | grep appletalk) ]]; then - # if it loaded, restart netatalk - sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart - else - # if we didn't load it successfully, delete it - sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk - fi - fi + # if AppleTalk module exists, try to load it + if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # module present, but not loaded? + sudo depmod + sudo modprobe appletalk + if [[ $(lsmod | grep appletalk) ]]; then + # if it loaded, restart netatalk + sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart + else + # if we didn't load it successfully, delete it + sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk + fi + fi - # if no AppleTalk module, try to download it from a2server site - if [[ ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # check for rpi kernel module - echo "A2SERVER: Installing AppleTalk kernel module for Raspbian..." - wget -qO /tmp/appletalk.ko.gz ${binaryURL}appletalk-$kernelRelease-rpi.ko.gz - if [[ $? -eq 0 ]]; then - # if we found a prebuilt one on a2server site, install it and load it - gunzip -f /tmp/appletalk.ko.gz &> /dev/null - sudo mkdir -p /lib/modules/$kernelRelease/kernel/net/appletalk - sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk - sudo depmod - sudo modprobe appletalk - if [[ $(lsmod | grep appletalk) ]]; then - # if it loaded, restart netatalk - sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart - else - # if we didn't load it successfully, remove it - sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null - fi - fi + # if no AppleTalk module, try to download it from a2server site + if [[ ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # check for rpi kernel module + echo "A2SERVER: Installing AppleTalk kernel module for Raspbian..." + wget -qO /tmp/appletalk.ko.gz ${binaryURL}appletalk-$kernelRelease-rpi.ko.gz + if [[ $? -eq 0 ]]; then + # if we found a prebuilt one on a2server site, install it and load it + gunzip -f /tmp/appletalk.ko.gz &> /dev/null + sudo mkdir -p /lib/modules/$kernelRelease/kernel/net/appletalk + sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk + sudo depmod + sudo modprobe appletalk + if [[ $(lsmod | grep appletalk) ]]; then + # if it loaded, restart netatalk + sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart + else + # if we didn't load it successfully, remove it + sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null + fi + fi - # if we still don't have AppleTalk, try to use rpi-update - rm /tmp/rpiUpdate 2> /dev/null - if [[ ! $(ps aux | grep [a]talkd) ]]; then - # use specific rpi-update commit (at https://github.com/Hexxeh/rpi-firmware/) - # from when AppleTalk was fixed, so we have a consistent firmware that - # we're loading until the next proper release of Raspbian that includes it - # 07-23-14: when AppleTalk was fixed after kernel panics in Raspbian 2014-06-20 (kernel 3.12.22+) - sudo rm /boot/.firmware_revision - sudo rpi-update cfd9a203590737f9536de70a1e01db25a3e8e069 - touch /tmp/rpiUpdate # so note to restart can display following install - fi + # if we still don't have AppleTalk, try to use rpi-update + rm /tmp/rpiUpdate 2> /dev/null + if [[ ! $(ps aux | grep [a]talkd) ]]; then + # use specific rpi-update commit (at https://github.com/Hexxeh/rpi-firmware/) + # from when AppleTalk was fixed, so we have a consistent firmware that + # we're loading until the next proper release of Raspbian that includes it + # 07-23-14: when AppleTalk was fixed after kernel panics in Raspbian 2014-06-20 (kernel 3.12.22+) + sudo rm /boot/.firmware_revision + sudo rpi-update cfd9a203590737f9536de70a1e01db25a3e8e069 + touch /tmp/rpiUpdate # so note to restart can display following install + fi - if [[ ! $(ps aux | grep [a]talkd) ]]; then - if [[ -f /tmp/rpiUpdate ]]; then - echo - echo "AppleTalk networking is installed but not yet active." - echo "When installation is complete, please restart your Raspberry Pi" - echo "when asked or by typing 'system-restart' at the Linux prompt" - echo "to allow Apple II computers to connect." - echo - else - echo - echo "AppleTalk networking could not be activated" - echo "for your Raspbian kernel version ($kernelRelease)." - echo "Please try restarting with 'system-restart'. If that doesn't work," - echo "you're not going to be able to connect from an Apple II." - echo "See http://appleii.ivanx.com/a2server for help." - echo - fi - fi - fi + if [[ ! $(ps aux | grep [a]talkd) ]]; then + if [[ -f /tmp/rpiUpdate ]]; then + echo + echo "AppleTalk networking is installed but not yet active." + echo "When installation is complete, please restart your Raspberry Pi" + echo "when asked or by typing 'system-restart' at the Linux prompt" + echo "to allow Apple II computers to connect." + echo + else + echo + echo "AppleTalk networking could not be activated" + echo "for your Raspbian kernel version ($kernelRelease)." + echo "Please try restarting with 'system-restart'. If that doesn't work," + echo "you're not going to be able to connect from an Apple II." + echo "See http://appleii.ivanx.com/a2server for help." + echo + fi + fi + fi fi if [[ $bground ]]; then - sudo sed -i 's/ATALK_BGROUND=no/ATALK_BGROUND=yes/' /etc/default/netatalk + sudo sed -i 's/ATALK_BGROUND=no/ATALK_BGROUND=yes/' /etc/default/netatalk fi # --- Set up Avahi-Daemon (Bonjour/mDNS) # thanks to: http://missingreadme.wordpress.com/2010/05/08/how-to-set-up-afp-filesharing-on-ubuntu if [[ ! $(dpkg -l avahi-daemon 2> /dev/null | grep ^ii) || ! $(dpkg -l libnss-mdns 2> /dev/null | grep ^ii) ]]; then - echo "A2SERVER: Installing Avahi-Daemon (Bonjour/mDNS)..." - if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then - # prepare for installing packages - sudo apt-get -y update - touch /tmp/a2server-packageReposUpdated - fi + echo "A2SERVER: Installing Avahi-Daemon (Bonjour/mDNS)..." + if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then + # prepare for installing packages + sudo apt-get -y update + touch /tmp/a2server-packageReposUpdated + fi - # Dependency: Bonjour for netatalk - sudo apt-get -y install avahi-daemon libnss-mdns &> /dev/null + # Dependency: Bonjour for netatalk + sudo apt-get -y install avahi-daemon libnss-mdns &> /dev/null fi sudo sed -i 's/^\(hosts.*\)$/\1 mdns/' /etc/nsswitch.conf if [[ ! -f /etc/avahi/services/afpd.service && ! -f /etc/avahi/services/afpd.service_disabled ]]; then - echo -e '\n\n\n %h\n \n _afpovertcp._tcp\n 548\n \n \n _device-info._tcp\n 0\n model=MacPro\n \n' | sudo tee /etc/avahi/services/afpd.service > /dev/null + echo -e '\n\n\n %h\n \n _afpovertcp._tcp\n 548\n \n \n _device-info._tcp\n 0\n model=MacPro\n \n' | sudo tee /etc/avahi/services/afpd.service > /dev/null fi sudo /etc/init.d/avahi-daemon restart &> /dev/null diff --git a/scripts/a2server-5-netboot.txt b/scripts/a2server-5-netboot.txt index e8f8216..4949245 100755 --- a/scripts/a2server-5-netboot.txt +++ b/scripts/a2server-5-netboot.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # this script downloads and installs the Apple boot blocks required # for booting an Apple II client over the network, and places @@ -9,12 +9,12 @@ # Ensure URL we'll use ends in a / case "$A2SERVER_SCRIPT_URL" in - */) scriptURL="$A2SERVER_SCRIPT_URL" ;; - *) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current}/" ;; + */) scriptURL="$A2SERVER_SCRIPT_URL" ;; + *) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current}/" ;; esac case "$A2SERVER_BINARY_URL" in - */) binaryURL="$A2SERVER_BINARY_URL" ;; - *) binaryURL="${A2SERVER_BINARY_URL:-http://ivanx.com/a2server/files}/" ;; + */) binaryURL="$A2SERVER_BINARY_URL" ;; + *) binaryURL="${A2SERVER_BINARY_URL:-http://ivanx.com/a2server/files}/" ;; esac useExternalURL=1 [[ $A2SERVER_NO_EXTERNAL ]] && useExternalURL= @@ -39,12 +39,12 @@ decToChar () { # arg: decimal number from 0-255 # out: one character #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg - [[ $1 ]] || return 11 - [[ $2 ]] && return 8 - [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ - && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 - # args are valid - echo -n -e "\x$(printf %02X "$1")" + [[ $1 ]] || return 11 + [[ $2 ]] && return 8 + [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ + && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 + # args are valid + echo -n -e "\x$(printf %02X "$1")" } charToDec () { @@ -54,117 +54,117 @@ charToDec () { # out: decimal value from 0-255 #exit: 8=extraneous arg, 9=invalid stdin, # 11=missing stdin/arg, 21=invalid arg - [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } - [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } - # arg/stdin is potentially valid (additional check below) - charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" - [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) - # above line verifies that arg/stdin is valid - [[ ${#charX} -ne 2 ]] && { echo -n 0; return 0; } - echo -n "${charX:0:1}" | od -t u1 | \ - head -1 | sed 's/[0\ ]*//' | tr -d ' \n' + [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } + [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } + # arg/stdin is potentially valid (additional check below) + charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" + [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) + # above line verifies that arg/stdin is valid + [[ ${#charX} -ne 2 ]] && { echo -n 0; return 0; } + echo -n "${charX:0:1}" | od -t u1 | \ + head -1 | sed 's/[0\ ]*//' | tr -d ' \n' } # --- end bashByter cpAD () { - # copy a file with its AppleDouble component in ./.AppleDouble - # arg1 = source path, # arg2 = destination directory (not filename) - afpsync= - if [[ $1 == "-s" ]]; then - afpsync=1 - shift - fi - arg1="$1" - [[ "$arg1" == *"/"* ]] || arg1="./$arg1" - cp -p "$arg1" "$2" - mkdir -p "$2"/.AppleDouble - cp -p "${arg1%/*}"/.AppleDouble/"${arg1##*/}" "$2"/.AppleDouble - [[ $afpsync ]] && afpsync -v > /dev/null + # copy a file with its AppleDouble component in ./.AppleDouble + # arg1 = source path, # arg2 = destination directory (not filename) + afpsync= + if [[ $1 == "-s" ]]; then + afpsync=1 + shift + fi + arg1="$1" + [[ "$arg1" == *"/"* ]] || arg1="./$arg1" + cp -p "$arg1" "$2" + mkdir -p "$2"/.AppleDouble + cp -p "${arg1%/*}"/.AppleDouble/"${arg1##*/}" "$2"/.AppleDouble + [[ $afpsync ]] && afpsync -v > /dev/null } checkP8YearTables () { - updateP8YearTables -c $1 - return $? + updateP8YearTables -c $1 + return $? } updateP8YearTables () { - # JC: Geoff Body and Andrew Roughan helped Joseph Carter with this one - # Update ProDOS 8 year table (and spalsh date because may as well) - # Effectively, we're turning p8 into the 6.0.2 or 6.0.3 version here. - # - # ID: updates the year table for the Thunderclock driver in ProDOS 8; - # calculated from the day of week and date, as year is unavailable. - # accepts optional arguments for custom patches - # arg1 = year table, comma separated - # arg2 = date string for ProDOS splash screen in format "dd-Mmm-yy" - # OR for presets, arg1=602 or arg1=603, arg2 is empty - check= - if [[ $1 == "-c" ]]; then - check=1 - shift - fi - patch1="" - patch2="" - if [[ $1 == "602" ]]; then - patch1=$(echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d") - patch2=$(echo -n -e "\xb2\xb2\xad\xca\xf5\xee\xad\xb1\xb5") - elif [[ $1 == "603" ]]; then - patch1=$(echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d") - patch2=$(echo -n -e "\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5") - elif [[ $1 ]]; then # year table supplied as seven comma-separated values - for year in $(tr "," " " <<< $1); do - patch1=${patch1}$(echo -n -e "\x$(printf %02X $year)") - done - if [[ $2 ]]; then # splash screen date supplied, convert to high-ascii bytes - for c in $(sed "s/./& /g" <<< $2); do - patch2=${patch2}$(decToChar $(( $(charToDec $c) + 128 ))) - done - fi - fi + # JC: Geoff Body and Andrew Roughan helped Joseph Carter with this one + # Update ProDOS 8 year table (and spalsh date because may as well) + # Effectively, we're turning p8 into the 6.0.2 or 6.0.3 version here. + # + # ID: updates the year table for the Thunderclock driver in ProDOS 8; + # calculated from the day of week and date, as year is unavailable. + # accepts optional arguments for custom patches + # arg1 = year table, comma separated + # arg2 = date string for ProDOS splash screen in format "dd-Mmm-yy" + # OR for presets, arg1=602 or arg1=603, arg2 is empty + check= + if [[ $1 == "-c" ]]; then + check=1 + shift + fi + patch1="" + patch2="" + if [[ $1 == "602" ]]; then + patch1=$(echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d") + patch2=$(echo -n -e "\xb2\xb2\xad\xca\xf5\xee\xad\xb1\xb5") + elif [[ $1 == "603" ]]; then + patch1=$(echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d") + patch2=$(echo -n -e "\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5") + elif [[ $1 ]]; then # year table supplied as seven comma-separated values + for year in $(tr "," " " <<< $1); do + patch1=${patch1}$(echo -n -e "\x$(printf %02X $year)") + done + if [[ $2 ]]; then # splash screen date supplied, convert to high-ascii bytes + for c in $(sed "s/./& /g" <<< $2); do + patch2=${patch2}$(decToChar $(( $(charToDec $c) + 128 ))) + done + fi + fi - wd=$PWD - cd /usr/local/etc/netatalk/a2boot - files=("p8" "ProDOS16 Image" "Apple :2f:2fe Boot Blocks" "$gsosDir/System/P8") - offset1=(3958 7030 7071 3958) # splash screen date - offset2=(38 3110 79 38) # year table + wd=$PWD + cd /usr/local/etc/netatalk/a2boot + files=("p8" "ProDOS16 Image" "Apple :2f:2fe Boot Blocks" "$gsosDir/System/P8") + offset1=(3958 7030 7071 3958) # splash screen date + offset2=(38 3110 79 38) # year table - i=0 - if [[ $check ]]; then - # check if patched -- we're not actually doing this any more; we're always patching - patched=0 # 0 is true in this case since it's the return value - while (( $i < ${#files[@]} )); do - [[ ! -f "${files[$i]}" ]] && { (( i++ )); continue; } - if [[ ! $patch1 || $patch1 != $(sudo dd if="${files[$i]}" skip=${offset1[$i]} bs=1 count=7 2> /dev/null) ]]; then - patched=1 # 1 is false - break - fi - if [[ ! $patch2 || $patch2 != $(sudo dd if="${files[$i]}" skip=${offset2[$i]} bs=1 count=9 2> /dev/null) ]]; then - patched=1 # 1 is false - break - fi - (( i++ )) - done - else - # perform patch - while (( $i < ${#files[@]} )); do - [[ ! -f "${files[$i]}" ]] && { (( i++ )); continue; } - [[ $patch1 ]] && echo -n -e ${patch1} | sudo dd of="${files[$i]}" seek=${offset1[$i]} bs=1 conv=notrunc 2> /dev/null - [[ $patch2 ]] && echo -n -e ${patch2} | sudo dd of="${files[$i]}" seek=${offset2[$i]} bs=1 conv=notrunc 2> /dev/null - (( i++ )) - done - patched=0 # 0 is true - fi - return $patched + i=0 + if [[ $check ]]; then + # check if patched -- we're not actually doing this any more; we're always patching + patched=0 # 0 is true in this case since it's the return value + while (( $i < ${#files[@]} )); do + [[ ! -f "${files[$i]}" ]] && { (( i++ )); continue; } + if [[ ! $patch1 || $patch1 != $(sudo dd if="${files[$i]}" skip=${offset1[$i]} bs=1 count=7 2> /dev/null) ]]; then + patched=1 # 1 is false + break + fi + if [[ ! $patch2 || $patch2 != $(sudo dd if="${files[$i]}" skip=${offset2[$i]} bs=1 count=9 2> /dev/null) ]]; then + patched=1 # 1 is false + break + fi + (( i++ )) + done + else + # perform patch + while (( $i < ${#files[@]} )); do + [[ ! -f "${files[$i]}" ]] && { (( i++ )); continue; } + [[ $patch1 ]] && echo -n -e ${patch1} | sudo dd of="${files[$i]}" seek=${offset1[$i]} bs=1 conv=notrunc 2> /dev/null + [[ $patch2 ]] && echo -n -e ${patch2} | sudo dd of="${files[$i]}" seek=${offset2[$i]} bs=1 conv=notrunc 2> /dev/null + (( i++ )) + done + patched=0 # 0 is true + fi + return $patched - # echo -n -e "\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5" | sudo dd of="p8" bs=38 seek=1 conv=notrunc 2> /dev/null - # echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d" | sudo dd of="p8" bs=3958 seek=1 conv=notrunc 2> /dev/null - # echo -n -e "\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5" | sudo dd of="ProDOS16 Image" bs=3110 seek=1 conv=notrunc 2> /dev/null - # echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d" | sudo dd of="ProDOS16 Image" bs=7030 seek=1 conv=notrunc 2> /dev/null - # echo -n -e "\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5" | sudo dd of="Apple :2f:2fe Boot Blocks" bs=79 seek=1 conv=notrunc 2> /dev/null - # echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d" | sudo dd of="Apple :2f:2fe Boot Blocks" bs=7071 seek=1 conv=notrunc 2> /dev/null + # echo -n -e "\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5" | sudo dd of="p8" bs=38 seek=1 conv=notrunc 2> /dev/null + # echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d" | sudo dd of="p8" bs=3958 seek=1 conv=notrunc 2> /dev/null + # echo -n -e "\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5" | sudo dd of="ProDOS16 Image" bs=3110 seek=1 conv=notrunc 2> /dev/null + # echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d" | sudo dd of="ProDOS16 Image" bs=7030 seek=1 conv=notrunc 2> /dev/null + # echo -n -e "\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5" | sudo dd of="Apple :2f:2fe Boot Blocks" bs=79 seek=1 conv=notrunc 2> /dev/null + # echo -n -e "\x12\x11\x0b\x10\x0f\x0e\x0d" | sudo dd of="Apple :2f:2fe Boot Blocks" bs=7071 seek=1 conv=notrunc 2> /dev/null - cd "$wd" + cd "$wd" } # bail out on automated netboot setup unless -b is also specified @@ -172,893 +172,893 @@ updateP8YearTables () { netbootInstalled= if [[ -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Boot\ Blocks && \ - -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Image && \ - -f /usr/local/etc/netatalk/a2boot/Apple\ :2f:2fe\ Boot\ Blocks && \ - -f /usr/local/etc/netatalk/a2boot/p8 && \ - -f /usr/local/etc/netatalk/a2boot/Basic.System && \ - -f $gsosDir/USERS/USER1/SETUP/ATINIT && \ - -f $gsosDir/USERS/""/SETUP/ATINIT ]] ; then - netbootInstalled=1 + -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Image && \ + -f /usr/local/etc/netatalk/a2boot/Apple\ :2f:2fe\ Boot\ Blocks && \ + -f /usr/local/etc/netatalk/a2boot/p8 && \ + -f /usr/local/etc/netatalk/a2boot/Basic.System && \ + -f $gsosDir/USERS/USER1/SETUP/ATINIT && \ + -f $gsosDir/USERS/""/SETUP/ATINIT ]] ; then + netbootInstalled=1 fi REPLY= if [[ ! $autoAnswerYes || -f /tmp/a2server-setupNetBoot ]]; then - if [[ ! $autoAnswerYes ]]; then - if [[ ! $netbootInstalled ]]; then - echo - echo "Do you want to set up A2SERVER to be able to boot Apple II" - echo -n "computers over the network? " - read - else - echo "A2SERVER is already set up to boot Apple II computers over the network." - fi - fi - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - - nbmode=1 - echo - - sudo true - mkdir -p /tmp/netboot - rm -r /tmp/netboot/* 2> /dev/null - cd /tmp/netboot - - # this will get "Disk 7" (Apple II Setup) as a raw (block dump) image - if [[ ! -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Boot\ Blocks ]] \ - || [[ ! -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Image ]] \ - || [[ ! -f /usr/local/etc/netatalk/a2boot/Apple\ :2f:2fe\ Boot\ Blocks ]] \ - || [[ ! -f /usr/local/etc/netatalk/a2boot/p8 ]] \ - || [[ ! -f /usr/local/etc/netatalk/a2boot/Basic.System ]]; then - echo "A2SERVER: Downloading Apple II Boot Blocks..." - cd /tmp/netboot - - if [[ $useExternalURL ]]; then - wget --max-redirect 0 -qO Disk_7_of_7-Apple_II_Setup.sea.bin ${gsosURL}Disk_7_of_7-Apple_II_Setup.sea.bin - unar -k skip Disk_7_of_7-Apple_II_Setup.sea.bin &> /dev/null - if (( $? != 0 )); then - wget -qO Disk_7_of_7-Apple_II_Setup.sea.bin ${gsosBackupURL}Disk_7_of_7-Apple_II_Setup.sea.bin - unar -k skip Disk_7_of_7-Apple_II_Setup.sea.bin &> /dev/null - fi - fi - if [[ ! -f 'Disk 7 of 7-Apple II Setup.sea' ]]; then - wget -qO Disk_7_of_7-Apple_II_Setup.sea.bin ${binaryURL}external/appleii/gsos601/Disk_7_of_7-Apple_II_Setup.sea.bin - unar -k skip Disk_7_of_7-Apple_II_Setup.sea.bin &> /dev/null - fi - truncate -s 819284 'Disk 7 of 7-Apple II Setup.sea' - dd if='Disk 7 of 7-Apple II Setup.sea' of=APPLE2SETUP.HDV bs=84 skip=1 2> /dev/null - - mkdir -p a2setup - sudo mount -t hfs -o ro,loop APPLE2SETUP.HDV a2setup - sudo mkdir -p /usr/local/etc/netatalk/a2boot - sudo rm -r /usr/local/etc/netatalk/a2boot/* 2> /dev/null - sudo cp -p a2setup/System\ Folder/* /usr/local/etc/netatalk/a2boot - sudo umount a2setup - sudo mv /usr/local/etc/netatalk/a2boot/Apple* /usr/local/etc/netatalk/a2boot/'Apple :2f:2fe Boot Blocks' - - cd /usr/local/etc/netatalk/a2boot - # thanks to Geoff Body for these Boot Blocks patches - # fix cleartext password login bug - echo -n -e "\xA8\xA2\x01\xBD\x80\x38\x99\xA0\x38\xC8\xE8\xE0\x09\x90\xF4" | \ - sudo dd of='Apple :2f:2fe Boot Blocks' bs=19779 seek=1 conv=notrunc 2> /dev/null - echo -n -e "\xA8\xA2\x01\xBD\x80\x10\x99\xA0\x10\xC8\xE8\xE0\x09\x90\xF4" | \ - sudo dd of='ProDOS16 Image' bs=22583 seek=1 conv=notrunc 2> /dev/null - # enable typing "8" during GS/OS netboot to force ProDOS 8 boot - echo -n -e "\x92" | sudo dd of='ProDOS16 Image' bs=256 seek=1 conv=notrunc 2> /dev/null - echo -n -e "\x20\x7d\x14" | sudo dd of='ProDOS16 Image' bs=864 seek=1 conv=notrunc 2> /dev/null - echo -n -e "\xad\x00\xc0\x29\xff\x00\xc9\xb8\x00\xd0\x06\xa9\x02\x00\x8d\x53\x14\xa9\x10\x0f\x60" | \ - sudo dd of='ProDOS16 Image' bs=1661 seek=1 conv=notrunc 2> /dev/null - fi - echo "A2SERVER: Boot Blocks have been installed." - - # get a2server-tools if necessary - if [[ ! -f /usr/local/bin/mkatinit ]] \ - || [[ ! -f /usr/local/bin/afptype ]] \ - || [[ ! -f /usr/local/bin/mkvolinfo ]] \ - || [[ ! -f /usr/local/bin/afpsync ]] \ - || [[ ! -f /usr/local/bin/cppo ]]; then - rm /tmp/2.tools &> /dev/null - wget -q -O /tmp/2.tools "${scriptURL}scripts/a2server-2-tools.txt" - chmod ugo+x /tmp/2.tools - /tmp/2.tools - rm /tmp/2.tools - fi - - # put BASIC.SYSTEM at root for ProDOS 8 startup - cp -p /usr/local/etc/netatalk/a2boot/Basic.System $gsosDir/BASIC.System - afpsync -v $gsosDir > /dev/null - afptype -p SYS -q $gsosDir/BASIC.System - - # create tools for setting GS/OS or ProDOS 8 boot in battery RAM and rebooting. Props yet again to Geoff Body. - if [[ ! -f $p8Dir/NETBOOT.P8 ]]; then - echo - echo "A2SERVER: Creating NETBOOT.P8..." - touch $p8Dir/NETBOOT.P8 - echo -n -e "\x38\x20\x1f\xfe\x90\x01\x60\xfb\x08\xc2\x30\xf4\x02\x00\xf4\x62\x00\xa2\x03\x0b\x22\x00\x00\xe1\x78\xf4\x00\x00\xf4\x00\x00\xab\xab\x2b\x38\xfb\xce\xf4\x03\xa9\x0c\x8d\x68\xc0\x9c\x47\xc0\x9c\x41\xc0\xa9\x09\x8d\x39\xc0\xa9\xc0\x8d\x39\xc0\x5c\x62\xfa\x00" \ - | sudo dd of="$p8Dir/NETBOOT.P8" 2> /dev/null - afpsync -v $p8Dir > /dev/null - afptype -p SYS -q $p8Dir/NETBOOT.P8 - fi - if [[ ! -f $gsosDir/NETBOOT.GSOS ]]; then - echo - echo "A2SERVER: Creating NETBOOT.GSOS..." - # create tool for setting GSOS boot in battery RAM and rebooting. Props yet again to Geoff Body. - touch $gsosDir/NETBOOT.GSOS - echo -n -e "\x38\x20\x1f\xfe\x90\x01\x60\xfb\x08\xc2\x30\xf4\x01\x00\xf4\x62\x00\xa2\x03\x0b\x22\x00\x00\xe1\x78\xf4\x00\x00\xf4\x00\x00\xab\xab\x2b\x38\xfb\xce\xf4\x03\xa9\x0c\x8d\x68\xc0\x9c\x47\xc0\x9c\x41\xc0\xa9\x09\x8d\x39\xc0\xa9\xc0\x8d\x39\xc0\x5c\x62\xfa\x00" \ - | sudo dd of="$p8Dir/NETBOOT.GSOS" 2> /dev/null - afpsync -v $gsosDir > /dev/null - afptype -p SYS -q $gsosDir/NETBOOT.GSOS - fi - - mkatinit -gs -d -f # GS/OS registered user and Guest starts up with SYSTEM/FINDER - mkatinit -d -f guest # ProDOS 8 Guest starts up with BASIC.SYSTEM (no registered user) - - netbootInstalled=1 - fi - - if [[ $netbootInstalled ]]; then - gsosInstall= - gsosReinstall=1 - if [[ -f "$gsosDir/SYSTEM/START.GS.OS" ]]; then - while true; do - gsosInstall= - gsosReinstall= - echo - echo "GS/OS is already installed on this volume." - echo "1: leave existing GS/OS system in place" - echo "2: delete installed GS/OS system, then install new GS/OS" - echo "3: install or upgrade GS/OS on top of existing GS/OS system" - echo - echo -n "Which would you like to do? " - read - if [[ $REPLY == "2" || $REPLY == "3" ]]; then - gsosReinstall=$REPLY - if (( $gsosReinstall == 2 )); then - echo - echo -n "Are you sure you want to delete your entire GS/OS System folder? " - read - if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - rm -r "$gsosDir/System"/* "$gsosDir/System/.AppleDouble"/* 2> /dev/null - afpsync &> /dev/null - echo - break - fi - else - echo -n "Are you sure you want to reinstall GS/OS over your existing system? " - read - if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - rm -r "$gsosDir/System/Start.GS.OS $gsosDir/System/.AppleDouble/Start.GS.OS" 2> /dev/null - afpsync &> /dev/null - echo - break - fi - fi - else - gsosInstall=1 - break - fi - done - fi - - if [[ $gsosReinstall ]]; then - if [[ ! $autoAnswerYes ]]; then - echo - echo "You can set up GS/OS for network boot. This may take a while." - echo - echo " 0: don't install GS/OS" - echo " 1: GS/OS 6.0.1 (May 1993) [official release]" - echo " The final version authorized by Apple. It has a few bugs," - echo " but most of these can be patched. Predictable and might be" - echo " required if you use certain patches." - echo " 2: GS/OS 6.0.2 (Jul 2015)" - echo " A community effort released by Antoine Vignau with fixes for" - echo " some serious bugs and a few other enhancements." - echo " 3: GS/OS 6.0.3 (Aug 2015)" - echo " Continuing community effort released by Tony Diaz. Includes" - echo " previous work along with additional fixes/changes. Better" - echo " documentation of changes. Most will prefer this or Apple's" - echo " release above." - echo - echo -n "Which flavor would you like? " - read - fi - [[ $autoAnswerYes ]] && gsosVersion=1 - if [[ $REPLY == "1" || $REPLY == "2" || $REPLY == "3" ]]; then - gsosInstall=$REPLY - - if [[ gsosInstall -gt 1 ]]; then - updateP8YearTables - fi - - # get GS/OS disks and put them in IMAGES - # also dump contents into NET.INSTALL and modify scripts to work from there - # echo - echo - echo "A2SERVER: Downloading GS/OS 6.0.${gsosInstall} installer disk images..." - mkdir -p /tmp/netboot - rm -r /tmp/netboot/* 2> /dev/null - cd /tmp/netboot - mkdir -p $imagesDir - mkdir -p $netInstallDir - activeDisk=0 - - diskNames=( Install System.Disk SystemTools1 SystemTools2 Fonts synthLAB ) - if (( $gsosInstall == 1 )); then - : - elif (( $gsosInstall == 2 )); then - gsosURL="http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Software/Operating%20Systems/Apple%20IIGS%20System/Disk%20Images/" - diskNames=( Install System.Disk SystemTools1 SystemTools2 SystemTools3 Fonts1 Fonts2 synthLAB ) - diskWebNames=( Install System%20disk System%20tools%201 System%20tools%202 System%20tools%203 Fonts%201 Fonts%202 Synthlab ) - elif (( $gsosInstall == 3 )); then - gsosURL="ftp://ftp.apple.asimov.net/pub/apple_II/images/gs/os/gsos/Apple_IIGS_System_6.0.3/" - fi - - # delete previously downloaded installer - rm "$imagesDir/* $imagesDir/.AppleDouble"/* 2> /dev/null - rm "$netInstallDir/* $netInstallDir/.AppleDouble"/* 2> /dev/null - afpsync -v $gsosDir > /dev/null - - for diskname in ${diskNames[@]}; do - outfile="$imagesDir/$diskname.po" - (( activeDisk++ )) - echo "A2SERVER: Disk ${activeDisk} of ${#diskNames[@]}: $diskname" - if (( $gsosInstall == 1 )); then - if [[ $useExternalURL ]]; then - wget --max-redirect 0 -qO "Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${gsosURL}Disk_${activeDisk}_of_7-${diskname}.sea.bin" - unar -k skip "Disk_${activeDisk}_of_7-${diskname}.sea.bin" &> /dev/null - if [[ ! -f "Disk ${activeDisk} of 7-${diskname}.sea" ]]; then - wget -qO "Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${gsosBackupURL}Disk_${activeDisk}_of_7-${diskname}.sea.bin" - unar -k skip "Disk_${activeDisk}_of_7-${diskname}.sea.bin" &> /dev/null - fi - fi - if [[ ! -f "Disk ${activeDisk} of 7-${diskname}.sea" ]]; then - wget -qO "Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${binaryURL}external/appleii/gsos601/Disk_${activeDisk}_of_7-${diskname}.sea.bin" - unar -k skip "Disk_${activeDisk}_of_7-${diskname}.sea.bin" &> /dev/null - fi - truncate -s 819284 "Disk ${activeDisk} of 7-${diskname}.sea" - dd if="Disk ${activeDisk} of 7-${diskname}.sea" of=${outfile} bs=84 skip=1 &> /dev/null - elif (( $gsosInstall == 2 )); then - if [[ $useExternalURL ]]; then - wget -qO $outfile "$gsosURL/IIGS%20System%206.0.2%20-%20Disk%20${activeDisk}%20${diskWebNames[$activeDisk-1]}.po" - fi - if [[ $? -ne 0 || ! -f $outfile ]]; then - wget -qO $outfile "${binaryURL}external/appleii/gsos602/$diskname.po" - fi - elif (( $gsosInstall == 3 )); then - if [[ $useExternalURL ]]; then - wget -qO $outfile "$gsosURL/$diskname.po" - fi - if [[ $? -ne 0 || ! -f $outfile ]]; then - wget -qO $outfile "${binaryURL}external/appleii/gsos603/$diskname.po" - fi - fi - cppo -s -ad $outfile $netInstallDir - done - rm *.sea* &> /dev/null - sed -i "s/\([^\\]\r:\)/\1A2FILES:GSOS.Installer:Net.Install:/g" $netInstallDir/Install/Scripts/* - - afpsync -v $gsosDir > /dev/null - - # install GS/OS - # spec for GS/OS installer scripts: GS/OS Tech Note #64 - # http://www.1000bit.it/support/manuali/apple/technotes/iigs/tn.iigs.064.html - processScript () { - scriptEntries=$(cat $1 | tr '\r' '#' | tr '~' '\n' | sed 's/4#D/5/') - IFS=$'\n' - scriptEntries=($scriptEntries) - pathPrefix="/A2FILES/GSOS.Installer/Net.Install"$(tr ':' '/' <<< ${scriptEntries[0]##S*\\\\#}) - entryCount=${#scriptEntries[@]} - (( entryCount -= 2 )) - # echo "entryCount: $entryCount" - entryIndex=2 - while (( entryIndex <= entryCount )); do - IFS='#' - scriptEntry=(${scriptEntries[entryIndex]}) - # echo $entryIndex $entryCount ${scriptEntry[@]} - action=${scriptEntry[1]:0:1} - sourcePathMixed=$(tr ':' '/' <<< ${scriptEntry[5]}) - [[ ${sourcePathMixed:0:1} != '/' ]] && sourcePathMixed="${pathPrefix}/$sourcePathMixed" - sourcePath=$sourcePathMixed - targetPath=$gsosDir/$(tr ':' '/' <<< ${scriptEntry[6]}) - # volumeName=$(cut -d/ -f 2 <<< $sourcePath) - targetParent=${targetPath%/*} - targetFile=${targetPath##*/} - sourceParent=${sourcePath%/*} - sourceFile=${sourcePath##*/} - - if [[ $action == 1 || $action == 2 ]]; then - mkdir -p $targetParent - echo "copying: $sourcePathMixed" - echo " to: $targetPath" - echo - [[ ! -d $targetParent ]] && mkdir -p $targetParent - cp -p ${gsosDir%/*}$sourcePath $targetPath - [[ ! -d $targetParent/.AppleDouble ]] && mkdir -p $targetParent/.AppleDouble - cp -p ${gsosDir%/*}$sourceParent/.AppleDouble/$sourceFile $targetParent/.AppleDouble/$targetFile - elif [[ $action == 3 || $action == 4 ]]; then - if [[ -f "$targetPath" ]]; then - echo "deleting $targetPath" - rm "$targetPath" - [[ -f $targetParent/.AppleDouble/$targetFile ]] && rm "$targetParent/.AppleDouble/$targetFile" - fi - fi - (( entryIndex++ )) - done - unset IFS - } - - mkdir -p /tmp/netboot - rm -r /tmp/netboot/* 2> /dev/null - cd /tmp/netboot - - echo "A2SERVER: Preparing GS/OS installer scripts..." - # work through installer scripts - echo "Script: Install.Sys.File" - processScript $netInstallDir/Install/Scripts/Instal.Sys.File - echo "Script: HFS.FST" - processScript $netInstallDir/Install/Scripts/HFS.FST - echo "Script: DOS33.FST" - processScript $netInstallDir/INSTALL/SCRIPTS/DOS3.3.FST - echo "Script: Teach" - processScript $netInstallDir/Install/Scripts/Teach - echo "Script: AppleShare" - processScript $netInstallDir/Install/Scripts/Appleshare - echo "Script: Server.Sys.File" - processScript $netInstallDir/Install/Scripts/Server.Sys.File - - # sync netatalk database - afpsync -v $gsosDir > /dev/null - else - gsosInstall= - fi - fi - - # if [[ ! $autoAnswerYes && (! $gsosInstall || $gsosInstall -lt 2) ]] && ! checkP8YearTables 603; then - # echo - # echo -n "Do you want to update the ProDOS 8 Thunderclock year table? " - # read - # fi - # if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - # updateP8YearTables 603 - # elif [[ $gsosInstall -ge 2 ]]; then - # updateP8YearTables 60${gsosInstall} - # fi - - # patch ProDOS 8 Thunderclock driver year table based on today's date - echo - echo "A2SERVER: Updating ProDOS 8 Thunderclock driver year table..." - mkdir -p /tmp/netboot - rm -r /tmp/netboot/* 2> /dev/null - wget -qO /tmp/netboot/clock.patch.py "${scriptURL}scripts/clock.patch.py" - updateP8YearTables $(python /tmp/netboot/clock.patch.py $(LANG=C date +"%a %m/%d/%y")) - - gsosInstalled="" - [[ -f "$gsosDir/System/Start.GS.OS" ]] && gsosInstalled="GS/OS and " - p8ToolsInstalled= - [[ -f $diskToolsP8Dir/SHRINKIT && -f $diskToolsP8Dir/DSK2FILE && -f $diskToolsP8Dir/SYSUTIL ]] && p8ToolsInstalled=1 - gsosToolsInstalled= - [[ -f $imageToolsDir/Asimov && -f $gsosDir/System/System.Setup/MountIt && -f $imageToolsDir/GSHK ]] && gsosToolsInstalled=1 - toolsInstalled= - if [[ $gsosInstalled ]]; then - [[ $gsosToolsInstalled && $p8ToolsInstalled ]] && toolsInstalled=1 - else - toolsInstalled=$p8ToolsInstalled - fi - REPLY= - if [[ ! $autoAnswerYes ]]; then - if [[ ! $toolsInstalled ]]; then - echo - echo "Do you want to download and install utilities for working with" - echo -n "disk images and archive files in ${gsosInstalled}ProDOS 8? " - read - else - echo - echo "A2SERVER: Disk image and archive utilities are already installed." - fi - fi - if [[ $gsosInstalled ]]; then - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - - # download image tools and put them in IMAGE.TOOLS - echo "A2SERVER: Downloading GS/OS disk image utilities..." - mkdir -p $imageToolsDir - - # get Asimov2 (for GS/OS) - echo -n "Asimov 2.0" - if [[ -f $imageToolsDir/Asimov ]]; then - echo " is already installed." - else - echo - cd /tmp/netboot - if [[ $useExternalURL ]]; then - wget -qO Asimov.shk http://www.ninjaforce.com/downloads/Asimov.shk - nulib2 -x -s Asimov.shk &> /dev/null - fi - if [[ ! -d Asimov ]]; then - wget -qO Asimov.shk ${binaryURL}external/appleii/Asimov.shk - nulib2 -x -s Asimov.shk &> /dev/null - fi - cp -p Asimov/Asimov $imageToolsDir/Asimov - afpsync -v $gsosDir > /dev/null - cat Asimov/Asimov_rsrc_ >> $imageToolsDir/.AppleDouble/Asimov - afptype -p S16 -q $imageToolsDir/Asimov - fi - - echo -n "GS-ShrinkIt 1.1" - # get GS-ShrinkIt - if [[ -f $imageToolsDir/GSHK ]]; then - echo " is already installed." - else - echo - mkdir -p /tmp/netboot/gshk - cd /tmp/netboot/gshk - if [[ $useExternalURL ]]; then - wget -qO gshk11.sea http://www.nulib.com/library/gshk11.sea - if (( $? != 0 )); then - wget -qO gshk11.sea http://web.archive.org/web/20131031160750/http://nulib.com/library/gshk11.sea - fi - nulib2 -x -s gshk11.sea &> /dev/null - fi - if [[ ! -f GSHK ]]; then - wget -qO gshk11.sea ${binaryURL}external/appleii/gshk11.sea - nulib2 -x -s gshk11.sea &> /dev/null - fi - cp -p GSHK $imageToolsDir/GSHK - afpsync -v $gsosDir > /dev/null - cat GSHK_rsrc_ >> $imageToolsDir/.AppleDouble/GSHK - afptype -p S16 -a DB07 -q $imageToolsDir/GSHK - cd /tmp/netboot - fi - - echo -n "MountIt 1.4" - # get MountIt (for GS/OS) - if [[ -f $gsosDir/System/System.Setup/MountIt ]]; then - echo " is already installed." - else - echo - mkdir -p /tmp/netboot/mountit - cd /tmp/netboot/mountit - if [[ $useExternalURL ]]; then - wget -q -O MOUNTIT.SHK http://www.brutaldeluxe.fr/products/apple2gs/MOUNTIT.SHK - if (( $? != 0 )); then - wget -q -O http://web.archive.org/web/20150201044930/http://brutaldeluxe.fr/products/apple2gs/MOUNTIT.SHK - fi - cppo -s -ad MOUNTIT.SHK System:System.Setup:MountIt . &> /dev/null - cppo -s -ad MOUNTIT.SHK ReadMe . &> /dev/null - fi - if [[ ! -f ReadMe ]]; then - wget -qO MOUNTIT.SHK ${binaryURL}external/appleii/MOUNTIT.SHK - cppo -s -ad MOUNTIT.SHK System:System.Setup:MountIt . &> /dev/null - cppo -s -ad MOUNTIT.SHK ReadMe . &> /dev/null - fi - cpAD ./MountIt $gsosDir/System/System.Setup - mkdir -p $gsosDir/GSOS.Installer/Image.Tools/MountIt - cpAD ./ReadMe $gsosDir/GSOS.Installer/Image.Tools/MountIt - afpsync -v $gsosDir > /dev/null - fi - fi - fi - - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - echo "A2SERVER: Downloading ProDOS 8 disk image utilities..." - - mkdir -p $diskToolsP8Dir - - echo -n "ShrinkIt 3.4" - # get ShrinkIt 3.4 (for ProDOS 8) - if [[ -f $diskToolsP8Dir/SHRINKIT ]]; then - echo " is already installed." - else - echo - cd /tmp/netboot - if [[ $useExternalURL ]]; then - wget -qO shrinkit.sdk http://www.nulib.com/library/shrinkit.sdk - if (( $? != 0 )); then - wget -qO shrinkit.sdk http://web.archive.org/web/20131031160750/http://www.nulib.com/library/shrinkit.sdk - fi - nulib2 -x -s -e shrinkit.sdk &> /dev/null - fi - if [[ ! -f "SHRINKIT#000118i" ]]; then - wget -qO shrinkit.sdk ${binaryURL}external/appleii/shrinkit.sdk - nulib2 -x -s -e shrinkit.sdk &> /dev/null - fi - cppo -s -ad "SHRINKIT#000118i" /SHRINKIT/SHRINKIT $diskToolsP8Dir &> /dev/null - afpsync -v $sharepath > /dev/null - fi - - echo -n "DSK2FILE 5.8" - # get DSK2FILE (for ProDOS 8) - if [[ -f $diskToolsP8Dir/DSK2FILE ]]; then - echo " is already installed." - else - echo - cd /tmp/netboot - if [[ $useExternalURL ]]; then - wget -q -O dsk2file.shk http://www.dwheeler.com/6502/oneelkruns/dsk2file.zip - nulib2 -x -s dsk2file.shk &> /dev/null - fi - if [[ ! -f DSK2FILE58 ]]; then - wget -qO dsk2file.shk ${binaryURL}external/appleii/dsk2file.shk - nulib2 -x -s dsk2file.shk &> /dev/null - fi - cp -p DSK2FILE58 $diskToolsP8Dir/DSK2FILE - afpsync -v $sharepath > /dev/null - afptype -p SYS -q $diskToolsP8Dir/DSK2FILE - fi - - echo -n "Apple System Utilities 3.1" - if [[ -f $diskToolsP8Dir/SYSUTIL ]]; then - echo " is already installed." - else - echo - cd /tmp/netboot - if [[ $useExternalURL ]]; then - wget --max-redirect 0 -qO Apple_II_System_Disk_3.2.sea.bin http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_II_Supplemental/Apple_II_System_Disk_3.2.sea.bin - if (( $? != 0 )); then - wget -qO Apple_II_System_Disk_3.2.sea.bin http://archive.org/download/download.info.apple.com.2012.11/download.info.apple.com.2012.11.zip/download.info.apple.com%2FApple_Support_Area%2FApple_Software_Updates%2FEnglish-North_American%2FApple_II%2FApple_II_Supplemental%2FApple_II_System_Disk_3.2.sea.bin - fi - unar -k skip Apple_II_System_Disk_3.2.sea.bin &> /dev/null - fi - if [[ ! -f 'Apple II System Disk 3.2.sea' ]]; then - wget -qO Apple_II_System_Disk_3.2.sea.bin ${binaryURL}external/appleii/Apple_II_System_Disk_3.2.sea.bin - unar -k skip Apple_II_System_Disk_3.2.sea.bin &> /dev/null - fi - truncate -s 819284 'Apple II System Disk 3.2.sea' - dd if='Apple II System Disk 3.2.sea' of=A2SYSDISK32.HDV bs=84 skip=1 2> /dev/null - cppo -s -ad A2SYSDISK32.HDV /UTILITIES/SYSUTIL.SYSTEM $diskToolsP8Dir/SYSUTIL &> /dev/null - cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.0 $diskToolsP8Dir &> /dev/null - cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.1 $diskToolsP8Dir &> /dev/null - cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.2 $diskToolsP8Dir &> /dev/null - afpsync -v $sharepath > /dev/null - fi - - fi - - p8CommInstalled= - [[ -f $commDir/ProTERM/PROTERM && -f $commDir/Z.Link/Z.LINK && -f $commDir/ADTPro/ADTPRO && -f $commDir/ADTPro/VSDRIVE ]] && p8CommInstalled=1 - gsosCommInstalled= - [[ -f $commDir/Spectrum/Spectrum && -f $commDir/SAM2/SAM2 && -f $commDir/SAFE2/SAFE2 && -f $commDir/SNAP/SNAP && -f $gsosDir/System/CDevs/TCPIP ]] && gsosCommInstalled=1 - commInstalled= - if [[ $gsosInstalled ]]; then - [[ $gsosCommInstalled && $p8CommInstalled ]] && commInstalled=1 - else - commInstalled=$p8CommInstalled - fi - REPLY= - if [[ ! $autoAnswerYes ]]; then - if [[ ! $commInstalled ]]; then - echo - echo "Do you want to download communications software for" - echo -n "$gsosInstalled""ProDOS 8? " - read - else - echo - echo "A2SERVER: Communications software is already installed." - fi - fi - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - - echo "A2SERVER: Downloading communications software..." - - mkdir -p $commDir - - if [[ $gsosInstalled ]]; then - - unset safeUrl samUrl snapUrl safeVer samVer snapVer - if [[ $useExternalURL ]]; then - html=$(wget -qO- http://speccie.co.uk/speccie/Site/Download_Centre_files/widget1_markup.html) - safeUrl=$(echo "$html" | grep -i 'safe2.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') - samUrl=$(echo "$html" | grep -i 'sam2.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') - snapUrl=$(echo "$html" | grep -i 'snap.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') - safeVer=$(echo $safeUrl | rev | cut -d '/' -f 1 | cut -d '.' -f 2 | rev | cut -c 5- | sed 's/./.&/g' | cut -c 2-) - samVer=$(echo $samUrl | rev | cut -d '/' -f 1 | cut -d '.' -f 2 | rev | cut -c 4- | sed 's/./.&/g' | cut -c 2-) - snapVer=$(echo $snapUrl | rev | cut -d '/' -f 1 | cut -d '.' -f 2 | rev | cut -c 5- | sed 's/./.&/g' | cut -c 2-) - spectrumVer=$(echo "$html" | grep 'Spectrum.*Gold.2mg' | tr '<>' '\n' | grep '^Spectrum.*2mg$' | cut -d ' ' -f 2) - fi - - echo -n "Spectrum $spectrumVer" - # get Spectrum - if [[ -f $commDir/Spectrum/Spectrum ]]; then - echo " is already installed." - else - echo - mkdir -p $commDir/Spectrum - # remove images that might have been installed by 1.2.5 - cd $commDir/Spectrum - rm SPECTRUM.HDV MANUALS.HDV SOUNDS.HDV EXTRAS.HDV &> /dev/null - # install Spectrum into GS/OS - mkdir -p /tmp/netboot/spectrum - cd /tmp/netboot/spectrum - if [[ $useExternalURL ]]; then - wget -qO spectrum_gold_2mg.zip http://www.speccie.co.uk/speccie/software/spectrum_gold_2mg.zip - unzip spectrum_gold_2mg.zip Spectrum.Gold.2mg &> /dev/null - fi - if [[ ! -f Spectrum.Gold.2mg || $(wc -c < Spectrum.Gold.2mg) -eq 0 ]]; then - wget -qO spectrum_gold_2mg.zip ${binaryURL}external/appleii/spectrum_gold_2mg.zip - unzip spectrum_gold_2mg.zip Spectrum.Gold.2mg &> /dev/null - fi - cppo -s -ad Spectrum.Gold.2mg . &> /dev/null - userFolder=$(tr [:lower:] [:upper:] <<< $USER) - - for thisFolder in \ - Installer/Extras/CDEvs^System/CDevs \ - Installer/Extras/Tools^System/Tools \ - Installer/Extras/Fonts^System/Fonts \ - Installer/Extras/System.Setup^System/System.Setup \ - Installer/Help^System/Desk.Accs \ - Installer/Spectrum.Sounds^System/Sounds \ - Spectrum.*/Add.Ons^USERS/$userFolder/Add.Ons \ - Spectrum.*/Spectrum.Script^USERS/$userFolder/Spectrum.Script \ - Spectrum.*/Add.Ons^Comm/Spectrum/Add.Ons \ - Spectrum.*/Spectrum.Script^Comm/Spectrum/Spectrum.Script \ - Manuals^Comm/Spectrum/Manuals - do - mkdir -p $gsosDir/"${thisFolder##*^}" - cp -R Spectrum.Gold/${thisFolder%%^*}/* $gsosDir/"${thisFolder##*^}" - mkdir -p $gsosDir/"${thisFolder##*^}"/.AppleDouble - cp -R Spectrum.Gold/${thisFolder%%^*}/.AppleDouble/* $gsosDir/"${thisFolder##*^}"/.AppleDouble - done - cpAD Spectrum.Gold/Installer/SoundPatch $commDir/Spectrum - cpAD Spectrum.Gold/Spectrum.*/Spectrum $commDir/Spectrum - afpsync -v $gsosDir > /dev/null - fi - - echo -n "Marinetti 3.0b8" - if [[ -f $gsosDir/System/CDevs/TCPIP ]]; then - echo " is already installed." - else - echo - mkdir -p /tmp/netboot/marinetti - cd /tmp/netboot/marinetti - - # Marinetti 3.0b1 -- had to repackage because installer is GS/OS self-contained app - wget -qO MarinettiB1.SHK ${binaryURL}appleii/MarinettiB1.SHK - cppo -ad -s -n MarinettiB1.SHK $gsosDir > /dev/null - - # TCP/IP update (3.0b8) - if [[ $useExternalURL ]]; then - wget -qO Marinetti3.0b8.po http://www.a2retrosystems.com/downloads/Marinetti3.0b8.po - fi - if [[ $? != 0 || ! -f Marinetti3.0b8.po || $(wc -c < Marinetti3.0b8.po) != "819200" ]]; then - wget -qO Marinetti3.0b8.po ${binaryURL}external/appleii/Marinetti3.0b8.po - fi - cppo -ad Marinetti3.0b8.po /MARINETTI3.0B8/TCPIP $gsosDir/System/System.Setup > /dev/null - cppo -ad Marinetti3.0b8.po /MARINETTI3.0B8/CHANGELOG.3.0B8 $commDir/Marinetti > /dev/null - - # PPP Scripted Link Layer update (1.3d4) - if [[ $useExternalURL ]]; then - wget -qO PPPX.1.3d4.SHK http://www.apple2.org/marinetti/PPPX.1.3d4.SHK - fi - if [[ $? != 0 || ! -f PPPX.1.3d4.SHK || $(wc -c < PPPX.1.3d4.SHK) != "22068" ]]; then - wget -qO PPPX.1.3d4.SHK ${binaryURL}external/appleii/PPPX.1.3d4.SHK - fi - cppo -ad -s PPPX.1.3d4.SHK . > /dev/null - cd PPPX.1.3d4 - cpAD PPP.scripted $gsosDir/System/TCPIP - cpAD PPP.Script.DOC $commDir/Marinetti/Documentation - mkdir -p $commDir/Marinetti/PPP.scripted - cpAD Connect.Script $commDir/Marinetti/PPP.scripted - cpAD ChangeLog $commDir/Marinetti/PPP.scripted - - # Uthernet Link Layer - if [[ $useExternalURL ]]; then - wget -qO uthernetll.bxy http://www.speccie.co.uk/speccie/software/uthernetll.bxy - fi - if [[ $? != 0 || ! -f uthernetll.bxy || $(wc -c < uthernetll.bxy) -eq 0 ]]; then - wget -qO uthernetll.bxy ${binaryURL}external/appleii/uthernetll.bxy - fi - cppo -ad -s -n uthernetll.bxy $gsosDir/System/TCPIP > /dev/null - - # Uthernet II Link Layer - if [[ $useExternalURL ]]; then - wget -qO uthernet2ll.bxy http://www.speccie.co.uk/speccie/software/uthernet2ll.bxy - fi - if [[ $? != 0 || ! -f uthernet2ll.bxy || $(wc -c < uthernet2ll.bxy) -eq 0 ]]; then - wget -qO uthernet2ll.bxy ${binaryURL}external/appleii/uthernet2ll.bxy - fi - cppo -ad -s -n uthernet2ll.bxy $gsosDir/System/TCPIP > /dev/null - - # MacIP Link Layer settings for A2SERVER - wget -qO- ${binaryURL}macip-prefs.tgz | tar Pxz - - afpsync -v $gsosDir > /dev/null - fi - - echo -n "SAFE2 $safeVer" - if [[ -f $commDir/SAFE2/SAFE2 ]]; then - echo " is already installed." - else - echo - mkdir -p $commDir/SAFE2 - mkdir -p /tmp/netboot/safe2 - cd /tmp/netboot/safe2 - if [[ $useExternalURL ]]; then - [[ ! $safeUrl ]] && safeUrl="http://www.speccie.co.uk/speccie/software/safe229.bxy" - wget -qO safe2.bxy "$safeUrl" - cppo -s -ad safe2.bxy . &> /dev/null - fi - if [[ ! -f SAFE2.Archive/Safe2 ]]; then - wget -qO safe2.bxy ${binaryURL}external/appleii/safe2.bxy - cppo -s -ad safe2.bxy . &> /dev/null - fi - cd SAFE2.Archive - cpAD Safe2 $commDir/SAFE2 - cpAD The.Manual $commDir/SAFE2 - cpAD Read.Me.First $commDir/SAFE2 - cpAD Version.History $commDir/SAFE2 - cpAD Fonts/SAFE.8 $gsosDir/System/Fonts - cpAD Fonts/Shaston.16 $gsosDir/System/Fonts - cpAD TimeZone/TimeZone $gsosDir/System/CDEvs - cpAD TimeZone/Tool056 $gsosDir/System/Tools - rm -r $gsosDir/System/Desk.Accs/Help.Files/SAFE2 2> /dev/null - mv Help/Help.Files/SAFE2 $gsosDir/System/Desk.Accs/Help.Files - wget -qO- ${binaryURL}safe2-setup.tgz | tar Pzx - - afpsync -v $gsosDir > /dev/null - fi - - echo -n "SAM2 $samVer" - if [[ -f $commDir/SAM2/SAM2 ]]; then - echo " is already installed." - else - echo - mkdir -p $commDir/SAM2 - mkdir -p $commDir/SAM2/SAM2.Data - mkdir -p /tmp/netboot/sam2 - cd /tmp/netboot/sam2 - if [[ $useExternalURL ]]; then - [[ ! $samUrl ]] && samUrl="http://www.speccie.co.uk/speccie/software/sam205.bxy" - wget -qO sam2.bxy "$samUrl" - cppo -s -ad sam2.bxy . &> /dev/null - fi - if [[ ! -f SAM2.Archive/SAM2/SAM2 ]]; then - wget -qO sam2.bxy ${binaryURL}external/appleii/sam2.bxy - cppo -s -ad sam2.bxy . &> /dev/null - fi - cd SAM2.Archive - cpAD SAM2/SAM2 $commDir/SAM2 - cpAD SAM2/SAM2.Data/Taglines $commDir/SAM2/SAM2.Data - cpAD Sounds/SP.Snds.Aux $gsosDir/System/Sounds - cpAD Fonts/SAM.8 $gsosDir/System/Fonts - cpAD Fonts/SAM.10 $gsosDir/System/Fonts - cpAD The.Manual $commDir/SAM2 - cpAD Read.Me.First $commDir/SAM2 - cpAD Version.History $commDir/SAM2 - rm -r $gsosDir/System/Desk.Accs/Help.Files/SAM2 2> /dev/null - mv Help/Help.Files/SAM2 $gsosDir/System/Desk.Accs/Help.Files - # cpAD Fonts/SIS.3.10 $gsosDir/System/Fonts - # cpAD Fonts/SIS.4.10 $gsosDir/System/Fonts - # cpAD Tools/HTMLTool/TOOL130 $gsosDir/System/Tools - # cpAD Tools/Hierarchic/Hierarchic $gsosDir/System/CDEvs - # cpAD Fonts/Shaston.16 $gsosDir/System/Fonts - - afpsync -v $gsosDir > /dev/null - fi - - echo -n "SNAP $snapVer" - if [[ -f $commDir/SNAP/SNAP ]]; then - echo " is already installed." - else - echo - mkdir -p $commDir/SNAP - mkdir -p /tmp/netboot/snap - cd /tmp/netboot/snap - if [[ $useExternalURL ]]; then - [[ ! $snapUrl ]] && snapUrl="http://www.speccie.co.uk/speccie/software/snap118.bxy" - wget -qO snap.bxy "$snapUrl" - cppo -s -ad snap.bxy . &> /dev/null - fi - if [[ ! -f SNAP.Archive/SNAP ]]; then - wget -qO snap.bxy ${binaryURL}external/appleii/snap.bxy - cppo -s -ad snap.bxy . &> /dev/null - fi - cd SNAP.Archive - cpAD SNAP $commDir/SNAP - cpAD Fonts/SNAP.8 $gsosDir/System/Fonts - cpAD Fonts/SNAP.10 $gsosDir/System/Fonts - cpAD The.Manual $commDir/SNAP - cpAD Read.Me.First $commDir/SNAP - cpAD Change.List $commDir/SNAP - cpAD Quick.Start $commDir/SNAP - rm -r $gsosDir/System/Desk.Accs/Help.Files/SNAP 2> /dev/null - mv Help/Help.Files/SNAP $gsosDir/System/Desk.Accs/Help.Files - wget -qO- ${binaryURL}snap-setup.tgz | tar Pzx - # cpAD Fonts/SIS.3.10 $gsosDir/System/Fonts - # cpAD Fonts/SIS.4.10 $gsosDir/System/Fonts - # cpAD Tools/HTMLTool/TOOL130 $gsosDir/System/Tools - # cpAD Tools/Hierarchic/Hierarchic $gsosDir/System/CDEvs - # cpAD Fonts/Shaston.16 $gsosDir/System/Fonts - - afpsync -v $gsosDir > /dev/null - fi - fi - - echo -n "ProTERM 3.1" - # get A2CLOUD disk and copy from there - if [[ -f $commDir/ProTERM/PROTERM ]]; then - echo " is already installed." - else - echo - mkdir -p $commDir/ProTERM - mkdir -p $commDir/ProTERM/.AppleDouble - cd /tmp/netboot - wget -qO A2CLOUD.HDV "${binaryURL}appleii/A2CLOUD.HDV" - cppo -s -ad A2CLOUD.HDV . &> /dev/null - cd A2CLOUD - mv *PT3* *PROTERM* $commDir/ProTERM - cd .AppleDouble - mv *PT3* *PROTERM* $commDir/ProTERM/.AppleDouble - afpsync -v $gsosDir > /dev/null - fi - - echo -n "Z-Link 12-15-91" - # get A2CLOUD disk and copy from there - if [[ -f $commDir/Z.Link/Z.LINK ]]; then - echo " is already installed." - else - echo - mkdir -p $commDir/Z.Link - mkdir -p $commDir/Z.Link/.AppleDouble - cd /tmp/netboot/A2CLOUD - mv Z.LINK $commDir/Z.Link - cd .AppleDouble - mv Z.LINK $commDir/Z.Link/.AppleDouble - afpsync -v $gsosDir > /dev/null - fi - - echo -n "ADTPro 2.0.1" - if [[ -f $commDir/ADTPro/ADTPRO ]]; then - echo " is already installed." - else - mkdir -p $commDir/ADTPro - mkdir -p $commDir/ADTPro/.AppleDouble - echo - cd /tmp/netboot/A2CLOUD - mv *ADTPRO* *VEDRIVE* *VSDRIVE* $commDir/ADTPro - cd .AppleDouble - mv *ADTPRO* *VEDRIVE* *VSDRIVE* $commDir/ADTPro/.AppleDouble - afpsync -v $gsosDir > /dev/null - fi - - fi - - # clean up - cd - - # rock and roll! - echo - - echo - if [[ $gsosInstall ]]; then - echo "GS/OS network boot (for registered user and Guest) and" - fi - echo "ProDOS 8 network boot (for Guest only) is now configured." - echo "See http://ivanx.com/a2server for info using it." - - fi - - REPLY= - if [[ -d $gsosDir/SYSTEM/SYSTEM.SETUP ]]; then - if [[ ! $autoAnswerYes ]]; then - if [[ ! -f $gsosDir/SYSTEM/SYSTEM.SETUP/ATALKIRQ ]]; then - echo - echo "Do you want to download the patch required for using" - echo -n "a Farallon LocalTalk-to-Ethernet bridge with GS/OS? " - read - else - echo - echo "A2SERVER: The Farallon bridge patch has already been installed." - fi - fi - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - # Farallon bridge patch for GS/OS courtesy of Geoff Body - echo "A2SERVER: Downloading Farallon bridge patch..." - wget -qO /tmp/FARALLON.PO "${binaryURL}appleii/FARALLON.B1.PO" &> /dev/null - cppo -s -ad /tmp/FARALLON.PO /ATALKPATCH/ATALKIRQ $gsosDir/SYSTEM/SYSTEM.SETUP &> /dev/null - echo - echo "A2SERVER: The Farallon bridge patch is installed." - echo - echo "Note: Farallon bridges can only be used in GS/OS (with this patch)" - echo "and Apple IIe computers. Apple IIgs computers which network boot" - echo "directly into ProDOS 8 will freeze after a few minutes." - fi - fi + if [[ ! $autoAnswerYes ]]; then + if [[ ! $netbootInstalled ]]; then + echo + echo "Do you want to set up A2SERVER to be able to boot Apple II" + echo -n "computers over the network? " + read + else + echo "A2SERVER is already set up to boot Apple II computers over the network." + fi + fi + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + + nbmode=1 + echo + + sudo true + mkdir -p /tmp/netboot + rm -r /tmp/netboot/* 2> /dev/null + cd /tmp/netboot + + # this will get "Disk 7" (Apple II Setup) as a raw (block dump) image + if [[ ! -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Boot\ Blocks ]] \ + || [[ ! -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Image ]] \ + || [[ ! -f /usr/local/etc/netatalk/a2boot/Apple\ :2f:2fe\ Boot\ Blocks ]] \ + || [[ ! -f /usr/local/etc/netatalk/a2boot/p8 ]] \ + || [[ ! -f /usr/local/etc/netatalk/a2boot/Basic.System ]]; then + echo "A2SERVER: Downloading Apple II Boot Blocks..." + cd /tmp/netboot + + if [[ $useExternalURL ]]; then + wget --max-redirect 0 -qO Disk_7_of_7-Apple_II_Setup.sea.bin ${gsosURL}Disk_7_of_7-Apple_II_Setup.sea.bin + unar -k skip Disk_7_of_7-Apple_II_Setup.sea.bin &> /dev/null + if (( $? != 0 )); then + wget -qO Disk_7_of_7-Apple_II_Setup.sea.bin ${gsosBackupURL}Disk_7_of_7-Apple_II_Setup.sea.bin + unar -k skip Disk_7_of_7-Apple_II_Setup.sea.bin &> /dev/null + fi + fi + if [[ ! -f 'Disk 7 of 7-Apple II Setup.sea' ]]; then + wget -qO Disk_7_of_7-Apple_II_Setup.sea.bin ${binaryURL}external/appleii/gsos601/Disk_7_of_7-Apple_II_Setup.sea.bin + unar -k skip Disk_7_of_7-Apple_II_Setup.sea.bin &> /dev/null + fi + truncate -s 819284 'Disk 7 of 7-Apple II Setup.sea' + dd if='Disk 7 of 7-Apple II Setup.sea' of=APPLE2SETUP.HDV bs=84 skip=1 2> /dev/null + + mkdir -p a2setup + sudo mount -t hfs -o ro,loop APPLE2SETUP.HDV a2setup + sudo mkdir -p /usr/local/etc/netatalk/a2boot + sudo rm -r /usr/local/etc/netatalk/a2boot/* 2> /dev/null + sudo cp -p a2setup/System\ Folder/* /usr/local/etc/netatalk/a2boot + sudo umount a2setup + sudo mv /usr/local/etc/netatalk/a2boot/Apple* /usr/local/etc/netatalk/a2boot/'Apple :2f:2fe Boot Blocks' + + cd /usr/local/etc/netatalk/a2boot + # thanks to Geoff Body for these Boot Blocks patches + # fix cleartext password login bug + echo -n -e "\xA8\xA2\x01\xBD\x80\x38\x99\xA0\x38\xC8\xE8\xE0\x09\x90\xF4" | \ + sudo dd of='Apple :2f:2fe Boot Blocks' bs=19779 seek=1 conv=notrunc 2> /dev/null + echo -n -e "\xA8\xA2\x01\xBD\x80\x10\x99\xA0\x10\xC8\xE8\xE0\x09\x90\xF4" | \ + sudo dd of='ProDOS16 Image' bs=22583 seek=1 conv=notrunc 2> /dev/null + # enable typing "8" during GS/OS netboot to force ProDOS 8 boot + echo -n -e "\x92" | sudo dd of='ProDOS16 Image' bs=256 seek=1 conv=notrunc 2> /dev/null + echo -n -e "\x20\x7d\x14" | sudo dd of='ProDOS16 Image' bs=864 seek=1 conv=notrunc 2> /dev/null + echo -n -e "\xad\x00\xc0\x29\xff\x00\xc9\xb8\x00\xd0\x06\xa9\x02\x00\x8d\x53\x14\xa9\x10\x0f\x60" | \ + sudo dd of='ProDOS16 Image' bs=1661 seek=1 conv=notrunc 2> /dev/null + fi + echo "A2SERVER: Boot Blocks have been installed." + + # get a2server-tools if necessary + if [[ ! -f /usr/local/bin/mkatinit ]] \ + || [[ ! -f /usr/local/bin/afptype ]] \ + || [[ ! -f /usr/local/bin/mkvolinfo ]] \ + || [[ ! -f /usr/local/bin/afpsync ]] \ + || [[ ! -f /usr/local/bin/cppo ]]; then + rm /tmp/2.tools &> /dev/null + wget -q -O /tmp/2.tools "${scriptURL}scripts/a2server-2-tools.txt" + chmod ugo+x /tmp/2.tools + /tmp/2.tools + rm /tmp/2.tools + fi + + # put BASIC.SYSTEM at root for ProDOS 8 startup + cp -p /usr/local/etc/netatalk/a2boot/Basic.System $gsosDir/BASIC.System + afpsync -v $gsosDir > /dev/null + afptype -p SYS -q $gsosDir/BASIC.System + + # create tools for setting GS/OS or ProDOS 8 boot in battery RAM and rebooting. Props yet again to Geoff Body. + if [[ ! -f $p8Dir/NETBOOT.P8 ]]; then + echo + echo "A2SERVER: Creating NETBOOT.P8..." + touch $p8Dir/NETBOOT.P8 + echo -n -e "\x38\x20\x1f\xfe\x90\x01\x60\xfb\x08\xc2\x30\xf4\x02\x00\xf4\x62\x00\xa2\x03\x0b\x22\x00\x00\xe1\x78\xf4\x00\x00\xf4\x00\x00\xab\xab\x2b\x38\xfb\xce\xf4\x03\xa9\x0c\x8d\x68\xc0\x9c\x47\xc0\x9c\x41\xc0\xa9\x09\x8d\x39\xc0\xa9\xc0\x8d\x39\xc0\x5c\x62\xfa\x00" \ + | sudo dd of="$p8Dir/NETBOOT.P8" 2> /dev/null + afpsync -v $p8Dir > /dev/null + afptype -p SYS -q $p8Dir/NETBOOT.P8 + fi + if [[ ! -f $gsosDir/NETBOOT.GSOS ]]; then + echo + echo "A2SERVER: Creating NETBOOT.GSOS..." + # create tool for setting GSOS boot in battery RAM and rebooting. Props yet again to Geoff Body. + touch $gsosDir/NETBOOT.GSOS + echo -n -e "\x38\x20\x1f\xfe\x90\x01\x60\xfb\x08\xc2\x30\xf4\x01\x00\xf4\x62\x00\xa2\x03\x0b\x22\x00\x00\xe1\x78\xf4\x00\x00\xf4\x00\x00\xab\xab\x2b\x38\xfb\xce\xf4\x03\xa9\x0c\x8d\x68\xc0\x9c\x47\xc0\x9c\x41\xc0\xa9\x09\x8d\x39\xc0\xa9\xc0\x8d\x39\xc0\x5c\x62\xfa\x00" \ + | sudo dd of="$p8Dir/NETBOOT.GSOS" 2> /dev/null + afpsync -v $gsosDir > /dev/null + afptype -p SYS -q $gsosDir/NETBOOT.GSOS + fi + + mkatinit -gs -d -f # GS/OS registered user and Guest starts up with SYSTEM/FINDER + mkatinit -d -f guest # ProDOS 8 Guest starts up with BASIC.SYSTEM (no registered user) + + netbootInstalled=1 + fi + + if [[ $netbootInstalled ]]; then + gsosInstall= + gsosReinstall=1 + if [[ -f "$gsosDir/SYSTEM/START.GS.OS" ]]; then + while true; do + gsosInstall= + gsosReinstall= + echo + echo "GS/OS is already installed on this volume." + echo "1: leave existing GS/OS system in place" + echo "2: delete installed GS/OS system, then install new GS/OS" + echo "3: install or upgrade GS/OS on top of existing GS/OS system" + echo + echo -n "Which would you like to do? " + read + if [[ $REPLY == "2" || $REPLY == "3" ]]; then + gsosReinstall=$REPLY + if (( $gsosReinstall == 2 )); then + echo + echo -n "Are you sure you want to delete your entire GS/OS System folder? " + read + if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + rm -r "$gsosDir/System"/* "$gsosDir/System/.AppleDouble"/* 2> /dev/null + afpsync &> /dev/null + echo + break + fi + else + echo -n "Are you sure you want to reinstall GS/OS over your existing system? " + read + if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + rm -r "$gsosDir/System/Start.GS.OS $gsosDir/System/.AppleDouble/Start.GS.OS" 2> /dev/null + afpsync &> /dev/null + echo + break + fi + fi + else + gsosInstall=1 + break + fi + done + fi + + if [[ $gsosReinstall ]]; then + if [[ ! $autoAnswerYes ]]; then + echo + echo "You can set up GS/OS for network boot. This may take a while." + echo + echo " 0: don't install GS/OS" + echo " 1: GS/OS 6.0.1 (May 1993) [official release]" + echo " The final version authorized by Apple. It has a few bugs," + echo " but most of these can be patched. Predictable and might be" + echo " required if you use certain patches." + echo " 2: GS/OS 6.0.2 (Jul 2015)" + echo " A community effort released by Antoine Vignau with fixes for" + echo " some serious bugs and a few other enhancements." + echo " 3: GS/OS 6.0.3 (Aug 2015)" + echo " Continuing community effort released by Tony Diaz. Includes" + echo " previous work along with additional fixes/changes. Better" + echo " documentation of changes. Most will prefer this or Apple's" + echo " release above." + echo + echo -n "Which flavor would you like? " + read + fi + [[ $autoAnswerYes ]] && gsosVersion=1 + if [[ $REPLY == "1" || $REPLY == "2" || $REPLY == "3" ]]; then + gsosInstall=$REPLY + + if [[ gsosInstall -gt 1 ]]; then + updateP8YearTables + fi + + # get GS/OS disks and put them in IMAGES + # also dump contents into NET.INSTALL and modify scripts to work from there + # echo + echo + echo "A2SERVER: Downloading GS/OS 6.0.${gsosInstall} installer disk images..." + mkdir -p /tmp/netboot + rm -r /tmp/netboot/* 2> /dev/null + cd /tmp/netboot + mkdir -p $imagesDir + mkdir -p $netInstallDir + activeDisk=0 + + diskNames=( Install System.Disk SystemTools1 SystemTools2 Fonts synthLAB ) + if (( $gsosInstall == 1 )); then + : + elif (( $gsosInstall == 2 )); then + gsosURL="http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Software/Operating%20Systems/Apple%20IIGS%20System/Disk%20Images/" + diskNames=( Install System.Disk SystemTools1 SystemTools2 SystemTools3 Fonts1 Fonts2 synthLAB ) + diskWebNames=( Install System%20disk System%20tools%201 System%20tools%202 System%20tools%203 Fonts%201 Fonts%202 Synthlab ) + elif (( $gsosInstall == 3 )); then + gsosURL="ftp://ftp.apple.asimov.net/pub/apple_II/images/gs/os/gsos/Apple_IIGS_System_6.0.3/" + fi + + # delete previously downloaded installer + rm "$imagesDir/* $imagesDir/.AppleDouble"/* 2> /dev/null + rm "$netInstallDir/* $netInstallDir/.AppleDouble"/* 2> /dev/null + afpsync -v $gsosDir > /dev/null + + for diskname in ${diskNames[@]}; do + outfile="$imagesDir/$diskname.po" + (( activeDisk++ )) + echo "A2SERVER: Disk ${activeDisk} of ${#diskNames[@]}: $diskname" + if (( $gsosInstall == 1 )); then + if [[ $useExternalURL ]]; then + wget --max-redirect 0 -qO "Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${gsosURL}Disk_${activeDisk}_of_7-${diskname}.sea.bin" + unar -k skip "Disk_${activeDisk}_of_7-${diskname}.sea.bin" &> /dev/null + if [[ ! -f "Disk ${activeDisk} of 7-${diskname}.sea" ]]; then + wget -qO "Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${gsosBackupURL}Disk_${activeDisk}_of_7-${diskname}.sea.bin" + unar -k skip "Disk_${activeDisk}_of_7-${diskname}.sea.bin" &> /dev/null + fi + fi + if [[ ! -f "Disk ${activeDisk} of 7-${diskname}.sea" ]]; then + wget -qO "Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${binaryURL}external/appleii/gsos601/Disk_${activeDisk}_of_7-${diskname}.sea.bin" + unar -k skip "Disk_${activeDisk}_of_7-${diskname}.sea.bin" &> /dev/null + fi + truncate -s 819284 "Disk ${activeDisk} of 7-${diskname}.sea" + dd if="Disk ${activeDisk} of 7-${diskname}.sea" of=${outfile} bs=84 skip=1 &> /dev/null + elif (( $gsosInstall == 2 )); then + if [[ $useExternalURL ]]; then + wget -qO $outfile "$gsosURL/IIGS%20System%206.0.2%20-%20Disk%20${activeDisk}%20${diskWebNames[$activeDisk-1]}.po" + fi + if [[ $? -ne 0 || ! -f $outfile ]]; then + wget -qO $outfile "${binaryURL}external/appleii/gsos602/$diskname.po" + fi + elif (( $gsosInstall == 3 )); then + if [[ $useExternalURL ]]; then + wget -qO $outfile "$gsosURL/$diskname.po" + fi + if [[ $? -ne 0 || ! -f $outfile ]]; then + wget -qO $outfile "${binaryURL}external/appleii/gsos603/$diskname.po" + fi + fi + cppo -s -ad $outfile $netInstallDir + done + rm *.sea* &> /dev/null + sed -i "s/\([^\\]\r:\)/\1A2FILES:GSOS.Installer:Net.Install:/g" $netInstallDir/Install/Scripts/* + + afpsync -v $gsosDir > /dev/null + + # install GS/OS + # spec for GS/OS installer scripts: GS/OS Tech Note #64 + # http://www.1000bit.it/support/manuali/apple/technotes/iigs/tn.iigs.064.html + processScript () { + scriptEntries=$(cat $1 | tr '\r' '#' | tr '~' '\n' | sed 's/4#D/5/') + IFS=$'\n' + scriptEntries=($scriptEntries) + pathPrefix="/A2FILES/GSOS.Installer/Net.Install"$(tr ':' '/' <<< ${scriptEntries[0]##S*\\\\#}) + entryCount=${#scriptEntries[@]} + (( entryCount -= 2 )) + # echo "entryCount: $entryCount" + entryIndex=2 + while (( entryIndex <= entryCount )); do + IFS='#' + scriptEntry=(${scriptEntries[entryIndex]}) + # echo $entryIndex $entryCount ${scriptEntry[@]} + action=${scriptEntry[1]:0:1} + sourcePathMixed=$(tr ':' '/' <<< ${scriptEntry[5]}) + [[ ${sourcePathMixed:0:1} != '/' ]] && sourcePathMixed="${pathPrefix}/$sourcePathMixed" + sourcePath=$sourcePathMixed + targetPath=$gsosDir/$(tr ':' '/' <<< ${scriptEntry[6]}) + # volumeName=$(cut -d/ -f 2 <<< $sourcePath) + targetParent=${targetPath%/*} + targetFile=${targetPath##*/} + sourceParent=${sourcePath%/*} + sourceFile=${sourcePath##*/} + + if [[ $action == 1 || $action == 2 ]]; then + mkdir -p $targetParent + echo "copying: $sourcePathMixed" + echo " to: $targetPath" + echo + [[ ! -d $targetParent ]] && mkdir -p $targetParent + cp -p ${gsosDir%/*}$sourcePath $targetPath + [[ ! -d $targetParent/.AppleDouble ]] && mkdir -p $targetParent/.AppleDouble + cp -p ${gsosDir%/*}$sourceParent/.AppleDouble/$sourceFile $targetParent/.AppleDouble/$targetFile + elif [[ $action == 3 || $action == 4 ]]; then + if [[ -f "$targetPath" ]]; then + echo "deleting $targetPath" + rm "$targetPath" + [[ -f $targetParent/.AppleDouble/$targetFile ]] && rm "$targetParent/.AppleDouble/$targetFile" + fi + fi + (( entryIndex++ )) + done + unset IFS + } + + mkdir -p /tmp/netboot + rm -r /tmp/netboot/* 2> /dev/null + cd /tmp/netboot + + echo "A2SERVER: Preparing GS/OS installer scripts..." + # work through installer scripts + echo "Script: Install.Sys.File" + processScript $netInstallDir/Install/Scripts/Instal.Sys.File + echo "Script: HFS.FST" + processScript $netInstallDir/Install/Scripts/HFS.FST + echo "Script: DOS33.FST" + processScript $netInstallDir/INSTALL/SCRIPTS/DOS3.3.FST + echo "Script: Teach" + processScript $netInstallDir/Install/Scripts/Teach + echo "Script: AppleShare" + processScript $netInstallDir/Install/Scripts/Appleshare + echo "Script: Server.Sys.File" + processScript $netInstallDir/Install/Scripts/Server.Sys.File + + # sync netatalk database + afpsync -v $gsosDir > /dev/null + else + gsosInstall= + fi + fi + + # if [[ ! $autoAnswerYes && (! $gsosInstall || $gsosInstall -lt 2) ]] && ! checkP8YearTables 603; then + # echo + # echo -n "Do you want to update the ProDOS 8 Thunderclock year table? " + # read + # fi + # if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + # updateP8YearTables 603 + # elif [[ $gsosInstall -ge 2 ]]; then + # updateP8YearTables 60${gsosInstall} + # fi + + # patch ProDOS 8 Thunderclock driver year table based on today's date + echo + echo "A2SERVER: Updating ProDOS 8 Thunderclock driver year table..." + mkdir -p /tmp/netboot + rm -r /tmp/netboot/* 2> /dev/null + wget -qO /tmp/netboot/clock.patch.py "${scriptURL}scripts/clock.patch.py" + updateP8YearTables $(python /tmp/netboot/clock.patch.py $(LANG=C date +"%a %m/%d/%y")) + + gsosInstalled="" + [[ -f "$gsosDir/System/Start.GS.OS" ]] && gsosInstalled="GS/OS and " + p8ToolsInstalled= + [[ -f $diskToolsP8Dir/SHRINKIT && -f $diskToolsP8Dir/DSK2FILE && -f $diskToolsP8Dir/SYSUTIL ]] && p8ToolsInstalled=1 + gsosToolsInstalled= + [[ -f $imageToolsDir/Asimov && -f $gsosDir/System/System.Setup/MountIt && -f $imageToolsDir/GSHK ]] && gsosToolsInstalled=1 + toolsInstalled= + if [[ $gsosInstalled ]]; then + [[ $gsosToolsInstalled && $p8ToolsInstalled ]] && toolsInstalled=1 + else + toolsInstalled=$p8ToolsInstalled + fi + REPLY= + if [[ ! $autoAnswerYes ]]; then + if [[ ! $toolsInstalled ]]; then + echo + echo "Do you want to download and install utilities for working with" + echo -n "disk images and archive files in ${gsosInstalled}ProDOS 8? " + read + else + echo + echo "A2SERVER: Disk image and archive utilities are already installed." + fi + fi + if [[ $gsosInstalled ]]; then + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + + # download image tools and put them in IMAGE.TOOLS + echo "A2SERVER: Downloading GS/OS disk image utilities..." + mkdir -p $imageToolsDir + + # get Asimov2 (for GS/OS) + echo -n "Asimov 2.0" + if [[ -f $imageToolsDir/Asimov ]]; then + echo " is already installed." + else + echo + cd /tmp/netboot + if [[ $useExternalURL ]]; then + wget -qO Asimov.shk http://www.ninjaforce.com/downloads/Asimov.shk + nulib2 -x -s Asimov.shk &> /dev/null + fi + if [[ ! -d Asimov ]]; then + wget -qO Asimov.shk ${binaryURL}external/appleii/Asimov.shk + nulib2 -x -s Asimov.shk &> /dev/null + fi + cp -p Asimov/Asimov $imageToolsDir/Asimov + afpsync -v $gsosDir > /dev/null + cat Asimov/Asimov_rsrc_ >> $imageToolsDir/.AppleDouble/Asimov + afptype -p S16 -q $imageToolsDir/Asimov + fi + + echo -n "GS-ShrinkIt 1.1" + # get GS-ShrinkIt + if [[ -f $imageToolsDir/GSHK ]]; then + echo " is already installed." + else + echo + mkdir -p /tmp/netboot/gshk + cd /tmp/netboot/gshk + if [[ $useExternalURL ]]; then + wget -qO gshk11.sea http://www.nulib.com/library/gshk11.sea + if (( $? != 0 )); then + wget -qO gshk11.sea http://web.archive.org/web/20131031160750/http://nulib.com/library/gshk11.sea + fi + nulib2 -x -s gshk11.sea &> /dev/null + fi + if [[ ! -f GSHK ]]; then + wget -qO gshk11.sea ${binaryURL}external/appleii/gshk11.sea + nulib2 -x -s gshk11.sea &> /dev/null + fi + cp -p GSHK $imageToolsDir/GSHK + afpsync -v $gsosDir > /dev/null + cat GSHK_rsrc_ >> $imageToolsDir/.AppleDouble/GSHK + afptype -p S16 -a DB07 -q $imageToolsDir/GSHK + cd /tmp/netboot + fi + + echo -n "MountIt 1.4" + # get MountIt (for GS/OS) + if [[ -f $gsosDir/System/System.Setup/MountIt ]]; then + echo " is already installed." + else + echo + mkdir -p /tmp/netboot/mountit + cd /tmp/netboot/mountit + if [[ $useExternalURL ]]; then + wget -q -O MOUNTIT.SHK http://www.brutaldeluxe.fr/products/apple2gs/MOUNTIT.SHK + if (( $? != 0 )); then + wget -q -O http://web.archive.org/web/20150201044930/http://brutaldeluxe.fr/products/apple2gs/MOUNTIT.SHK + fi + cppo -s -ad MOUNTIT.SHK System:System.Setup:MountIt . &> /dev/null + cppo -s -ad MOUNTIT.SHK ReadMe . &> /dev/null + fi + if [[ ! -f ReadMe ]]; then + wget -qO MOUNTIT.SHK ${binaryURL}external/appleii/MOUNTIT.SHK + cppo -s -ad MOUNTIT.SHK System:System.Setup:MountIt . &> /dev/null + cppo -s -ad MOUNTIT.SHK ReadMe . &> /dev/null + fi + cpAD ./MountIt $gsosDir/System/System.Setup + mkdir -p $gsosDir/GSOS.Installer/Image.Tools/MountIt + cpAD ./ReadMe $gsosDir/GSOS.Installer/Image.Tools/MountIt + afpsync -v $gsosDir > /dev/null + fi + fi + fi + + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + echo "A2SERVER: Downloading ProDOS 8 disk image utilities..." + + mkdir -p $diskToolsP8Dir + + echo -n "ShrinkIt 3.4" + # get ShrinkIt 3.4 (for ProDOS 8) + if [[ -f $diskToolsP8Dir/SHRINKIT ]]; then + echo " is already installed." + else + echo + cd /tmp/netboot + if [[ $useExternalURL ]]; then + wget -qO shrinkit.sdk http://www.nulib.com/library/shrinkit.sdk + if (( $? != 0 )); then + wget -qO shrinkit.sdk http://web.archive.org/web/20131031160750/http://www.nulib.com/library/shrinkit.sdk + fi + nulib2 -x -s -e shrinkit.sdk &> /dev/null + fi + if [[ ! -f "SHRINKIT#000118i" ]]; then + wget -qO shrinkit.sdk ${binaryURL}external/appleii/shrinkit.sdk + nulib2 -x -s -e shrinkit.sdk &> /dev/null + fi + cppo -s -ad "SHRINKIT#000118i" /SHRINKIT/SHRINKIT $diskToolsP8Dir &> /dev/null + afpsync -v $sharepath > /dev/null + fi + + echo -n "DSK2FILE 5.8" + # get DSK2FILE (for ProDOS 8) + if [[ -f $diskToolsP8Dir/DSK2FILE ]]; then + echo " is already installed." + else + echo + cd /tmp/netboot + if [[ $useExternalURL ]]; then + wget -q -O dsk2file.shk http://www.dwheeler.com/6502/oneelkruns/dsk2file.zip + nulib2 -x -s dsk2file.shk &> /dev/null + fi + if [[ ! -f DSK2FILE58 ]]; then + wget -qO dsk2file.shk ${binaryURL}external/appleii/dsk2file.shk + nulib2 -x -s dsk2file.shk &> /dev/null + fi + cp -p DSK2FILE58 $diskToolsP8Dir/DSK2FILE + afpsync -v $sharepath > /dev/null + afptype -p SYS -q $diskToolsP8Dir/DSK2FILE + fi + + echo -n "Apple System Utilities 3.1" + if [[ -f $diskToolsP8Dir/SYSUTIL ]]; then + echo " is already installed." + else + echo + cd /tmp/netboot + if [[ $useExternalURL ]]; then + wget --max-redirect 0 -qO Apple_II_System_Disk_3.2.sea.bin http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_II_Supplemental/Apple_II_System_Disk_3.2.sea.bin + if (( $? != 0 )); then + wget -qO Apple_II_System_Disk_3.2.sea.bin http://archive.org/download/download.info.apple.com.2012.11/download.info.apple.com.2012.11.zip/download.info.apple.com%2FApple_Support_Area%2FApple_Software_Updates%2FEnglish-North_American%2FApple_II%2FApple_II_Supplemental%2FApple_II_System_Disk_3.2.sea.bin + fi + unar -k skip Apple_II_System_Disk_3.2.sea.bin &> /dev/null + fi + if [[ ! -f 'Apple II System Disk 3.2.sea' ]]; then + wget -qO Apple_II_System_Disk_3.2.sea.bin ${binaryURL}external/appleii/Apple_II_System_Disk_3.2.sea.bin + unar -k skip Apple_II_System_Disk_3.2.sea.bin &> /dev/null + fi + truncate -s 819284 'Apple II System Disk 3.2.sea' + dd if='Apple II System Disk 3.2.sea' of=A2SYSDISK32.HDV bs=84 skip=1 2> /dev/null + cppo -s -ad A2SYSDISK32.HDV /UTILITIES/SYSUTIL.SYSTEM $diskToolsP8Dir/SYSUTIL &> /dev/null + cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.0 $diskToolsP8Dir &> /dev/null + cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.1 $diskToolsP8Dir &> /dev/null + cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.2 $diskToolsP8Dir &> /dev/null + afpsync -v $sharepath > /dev/null + fi + + fi + + p8CommInstalled= + [[ -f $commDir/ProTERM/PROTERM && -f $commDir/Z.Link/Z.LINK && -f $commDir/ADTPro/ADTPRO && -f $commDir/ADTPro/VSDRIVE ]] && p8CommInstalled=1 + gsosCommInstalled= + [[ -f $commDir/Spectrum/Spectrum && -f $commDir/SAM2/SAM2 && -f $commDir/SAFE2/SAFE2 && -f $commDir/SNAP/SNAP && -f $gsosDir/System/CDevs/TCPIP ]] && gsosCommInstalled=1 + commInstalled= + if [[ $gsosInstalled ]]; then + [[ $gsosCommInstalled && $p8CommInstalled ]] && commInstalled=1 + else + commInstalled=$p8CommInstalled + fi + REPLY= + if [[ ! $autoAnswerYes ]]; then + if [[ ! $commInstalled ]]; then + echo + echo "Do you want to download communications software for" + echo -n "$gsosInstalled""ProDOS 8? " + read + else + echo + echo "A2SERVER: Communications software is already installed." + fi + fi + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + + echo "A2SERVER: Downloading communications software..." + + mkdir -p $commDir + + if [[ $gsosInstalled ]]; then + + unset safeUrl samUrl snapUrl safeVer samVer snapVer + if [[ $useExternalURL ]]; then + html=$(wget -qO- http://speccie.co.uk/speccie/Site/Download_Centre_files/widget1_markup.html) + safeUrl=$(echo "$html" | grep -i 'safe2.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') + samUrl=$(echo "$html" | grep -i 'sam2.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') + snapUrl=$(echo "$html" | grep -i 'snap.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') + safeVer=$(echo $safeUrl | rev | cut -d '/' -f 1 | cut -d '.' -f 2 | rev | cut -c 5- | sed 's/./.&/g' | cut -c 2-) + samVer=$(echo $samUrl | rev | cut -d '/' -f 1 | cut -d '.' -f 2 | rev | cut -c 4- | sed 's/./.&/g' | cut -c 2-) + snapVer=$(echo $snapUrl | rev | cut -d '/' -f 1 | cut -d '.' -f 2 | rev | cut -c 5- | sed 's/./.&/g' | cut -c 2-) + spectrumVer=$(echo "$html" | grep 'Spectrum.*Gold.2mg' | tr '<>' '\n' | grep '^Spectrum.*2mg$' | cut -d ' ' -f 2) + fi + + echo -n "Spectrum $spectrumVer" + # get Spectrum + if [[ -f $commDir/Spectrum/Spectrum ]]; then + echo " is already installed." + else + echo + mkdir -p $commDir/Spectrum + # remove images that might have been installed by 1.2.5 + cd $commDir/Spectrum + rm SPECTRUM.HDV MANUALS.HDV SOUNDS.HDV EXTRAS.HDV &> /dev/null + # install Spectrum into GS/OS + mkdir -p /tmp/netboot/spectrum + cd /tmp/netboot/spectrum + if [[ $useExternalURL ]]; then + wget -qO spectrum_gold_2mg.zip http://www.speccie.co.uk/speccie/software/spectrum_gold_2mg.zip + unzip spectrum_gold_2mg.zip Spectrum.Gold.2mg &> /dev/null + fi + if [[ ! -f Spectrum.Gold.2mg || $(wc -c < Spectrum.Gold.2mg) -eq 0 ]]; then + wget -qO spectrum_gold_2mg.zip ${binaryURL}external/appleii/spectrum_gold_2mg.zip + unzip spectrum_gold_2mg.zip Spectrum.Gold.2mg &> /dev/null + fi + cppo -s -ad Spectrum.Gold.2mg . &> /dev/null + userFolder=$(tr [:lower:] [:upper:] <<< $USER) + + for thisFolder in \ + Installer/Extras/CDEvs^System/CDevs \ + Installer/Extras/Tools^System/Tools \ + Installer/Extras/Fonts^System/Fonts \ + Installer/Extras/System.Setup^System/System.Setup \ + Installer/Help^System/Desk.Accs \ + Installer/Spectrum.Sounds^System/Sounds \ + Spectrum.*/Add.Ons^USERS/$userFolder/Add.Ons \ + Spectrum.*/Spectrum.Script^USERS/$userFolder/Spectrum.Script \ + Spectrum.*/Add.Ons^Comm/Spectrum/Add.Ons \ + Spectrum.*/Spectrum.Script^Comm/Spectrum/Spectrum.Script \ + Manuals^Comm/Spectrum/Manuals + do + mkdir -p $gsosDir/"${thisFolder##*^}" + cp -R Spectrum.Gold/${thisFolder%%^*}/* $gsosDir/"${thisFolder##*^}" + mkdir -p $gsosDir/"${thisFolder##*^}"/.AppleDouble + cp -R Spectrum.Gold/${thisFolder%%^*}/.AppleDouble/* $gsosDir/"${thisFolder##*^}"/.AppleDouble + done + cpAD Spectrum.Gold/Installer/SoundPatch $commDir/Spectrum + cpAD Spectrum.Gold/Spectrum.*/Spectrum $commDir/Spectrum + afpsync -v $gsosDir > /dev/null + fi + + echo -n "Marinetti 3.0b8" + if [[ -f $gsosDir/System/CDevs/TCPIP ]]; then + echo " is already installed." + else + echo + mkdir -p /tmp/netboot/marinetti + cd /tmp/netboot/marinetti + + # Marinetti 3.0b1 -- had to repackage because installer is GS/OS self-contained app + wget -qO MarinettiB1.SHK ${binaryURL}appleii/MarinettiB1.SHK + cppo -ad -s -n MarinettiB1.SHK $gsosDir > /dev/null + + # TCP/IP update (3.0b8) + if [[ $useExternalURL ]]; then + wget -qO Marinetti3.0b8.po http://www.a2retrosystems.com/downloads/Marinetti3.0b8.po + fi + if [[ $? != 0 || ! -f Marinetti3.0b8.po || $(wc -c < Marinetti3.0b8.po) != "819200" ]]; then + wget -qO Marinetti3.0b8.po ${binaryURL}external/appleii/Marinetti3.0b8.po + fi + cppo -ad Marinetti3.0b8.po /MARINETTI3.0B8/TCPIP $gsosDir/System/System.Setup > /dev/null + cppo -ad Marinetti3.0b8.po /MARINETTI3.0B8/CHANGELOG.3.0B8 $commDir/Marinetti > /dev/null + + # PPP Scripted Link Layer update (1.3d4) + if [[ $useExternalURL ]]; then + wget -qO PPPX.1.3d4.SHK http://www.apple2.org/marinetti/PPPX.1.3d4.SHK + fi + if [[ $? != 0 || ! -f PPPX.1.3d4.SHK || $(wc -c < PPPX.1.3d4.SHK) != "22068" ]]; then + wget -qO PPPX.1.3d4.SHK ${binaryURL}external/appleii/PPPX.1.3d4.SHK + fi + cppo -ad -s PPPX.1.3d4.SHK . > /dev/null + cd PPPX.1.3d4 + cpAD PPP.scripted $gsosDir/System/TCPIP + cpAD PPP.Script.DOC $commDir/Marinetti/Documentation + mkdir -p $commDir/Marinetti/PPP.scripted + cpAD Connect.Script $commDir/Marinetti/PPP.scripted + cpAD ChangeLog $commDir/Marinetti/PPP.scripted + + # Uthernet Link Layer + if [[ $useExternalURL ]]; then + wget -qO uthernetll.bxy http://www.speccie.co.uk/speccie/software/uthernetll.bxy + fi + if [[ $? != 0 || ! -f uthernetll.bxy || $(wc -c < uthernetll.bxy) -eq 0 ]]; then + wget -qO uthernetll.bxy ${binaryURL}external/appleii/uthernetll.bxy + fi + cppo -ad -s -n uthernetll.bxy $gsosDir/System/TCPIP > /dev/null + + # Uthernet II Link Layer + if [[ $useExternalURL ]]; then + wget -qO uthernet2ll.bxy http://www.speccie.co.uk/speccie/software/uthernet2ll.bxy + fi + if [[ $? != 0 || ! -f uthernet2ll.bxy || $(wc -c < uthernet2ll.bxy) -eq 0 ]]; then + wget -qO uthernet2ll.bxy ${binaryURL}external/appleii/uthernet2ll.bxy + fi + cppo -ad -s -n uthernet2ll.bxy $gsosDir/System/TCPIP > /dev/null + + # MacIP Link Layer settings for A2SERVER + wget -qO- ${binaryURL}macip-prefs.tgz | tar Pxz + + afpsync -v $gsosDir > /dev/null + fi + + echo -n "SAFE2 $safeVer" + if [[ -f $commDir/SAFE2/SAFE2 ]]; then + echo " is already installed." + else + echo + mkdir -p $commDir/SAFE2 + mkdir -p /tmp/netboot/safe2 + cd /tmp/netboot/safe2 + if [[ $useExternalURL ]]; then + [[ ! $safeUrl ]] && safeUrl="http://www.speccie.co.uk/speccie/software/safe229.bxy" + wget -qO safe2.bxy "$safeUrl" + cppo -s -ad safe2.bxy . &> /dev/null + fi + if [[ ! -f SAFE2.Archive/Safe2 ]]; then + wget -qO safe2.bxy ${binaryURL}external/appleii/safe2.bxy + cppo -s -ad safe2.bxy . &> /dev/null + fi + cd SAFE2.Archive + cpAD Safe2 $commDir/SAFE2 + cpAD The.Manual $commDir/SAFE2 + cpAD Read.Me.First $commDir/SAFE2 + cpAD Version.History $commDir/SAFE2 + cpAD Fonts/SAFE.8 $gsosDir/System/Fonts + cpAD Fonts/Shaston.16 $gsosDir/System/Fonts + cpAD TimeZone/TimeZone $gsosDir/System/CDEvs + cpAD TimeZone/Tool056 $gsosDir/System/Tools + rm -r $gsosDir/System/Desk.Accs/Help.Files/SAFE2 2> /dev/null + mv Help/Help.Files/SAFE2 $gsosDir/System/Desk.Accs/Help.Files + wget -qO- ${binaryURL}safe2-setup.tgz | tar Pzx + + afpsync -v $gsosDir > /dev/null + fi + + echo -n "SAM2 $samVer" + if [[ -f $commDir/SAM2/SAM2 ]]; then + echo " is already installed." + else + echo + mkdir -p $commDir/SAM2 + mkdir -p $commDir/SAM2/SAM2.Data + mkdir -p /tmp/netboot/sam2 + cd /tmp/netboot/sam2 + if [[ $useExternalURL ]]; then + [[ ! $samUrl ]] && samUrl="http://www.speccie.co.uk/speccie/software/sam205.bxy" + wget -qO sam2.bxy "$samUrl" + cppo -s -ad sam2.bxy . &> /dev/null + fi + if [[ ! -f SAM2.Archive/SAM2/SAM2 ]]; then + wget -qO sam2.bxy ${binaryURL}external/appleii/sam2.bxy + cppo -s -ad sam2.bxy . &> /dev/null + fi + cd SAM2.Archive + cpAD SAM2/SAM2 $commDir/SAM2 + cpAD SAM2/SAM2.Data/Taglines $commDir/SAM2/SAM2.Data + cpAD Sounds/SP.Snds.Aux $gsosDir/System/Sounds + cpAD Fonts/SAM.8 $gsosDir/System/Fonts + cpAD Fonts/SAM.10 $gsosDir/System/Fonts + cpAD The.Manual $commDir/SAM2 + cpAD Read.Me.First $commDir/SAM2 + cpAD Version.History $commDir/SAM2 + rm -r $gsosDir/System/Desk.Accs/Help.Files/SAM2 2> /dev/null + mv Help/Help.Files/SAM2 $gsosDir/System/Desk.Accs/Help.Files + # cpAD Fonts/SIS.3.10 $gsosDir/System/Fonts + # cpAD Fonts/SIS.4.10 $gsosDir/System/Fonts + # cpAD Tools/HTMLTool/TOOL130 $gsosDir/System/Tools + # cpAD Tools/Hierarchic/Hierarchic $gsosDir/System/CDEvs + # cpAD Fonts/Shaston.16 $gsosDir/System/Fonts + + afpsync -v $gsosDir > /dev/null + fi + + echo -n "SNAP $snapVer" + if [[ -f $commDir/SNAP/SNAP ]]; then + echo " is already installed." + else + echo + mkdir -p $commDir/SNAP + mkdir -p /tmp/netboot/snap + cd /tmp/netboot/snap + if [[ $useExternalURL ]]; then + [[ ! $snapUrl ]] && snapUrl="http://www.speccie.co.uk/speccie/software/snap118.bxy" + wget -qO snap.bxy "$snapUrl" + cppo -s -ad snap.bxy . &> /dev/null + fi + if [[ ! -f SNAP.Archive/SNAP ]]; then + wget -qO snap.bxy ${binaryURL}external/appleii/snap.bxy + cppo -s -ad snap.bxy . &> /dev/null + fi + cd SNAP.Archive + cpAD SNAP $commDir/SNAP + cpAD Fonts/SNAP.8 $gsosDir/System/Fonts + cpAD Fonts/SNAP.10 $gsosDir/System/Fonts + cpAD The.Manual $commDir/SNAP + cpAD Read.Me.First $commDir/SNAP + cpAD Change.List $commDir/SNAP + cpAD Quick.Start $commDir/SNAP + rm -r $gsosDir/System/Desk.Accs/Help.Files/SNAP 2> /dev/null + mv Help/Help.Files/SNAP $gsosDir/System/Desk.Accs/Help.Files + wget -qO- ${binaryURL}snap-setup.tgz | tar Pzx + # cpAD Fonts/SIS.3.10 $gsosDir/System/Fonts + # cpAD Fonts/SIS.4.10 $gsosDir/System/Fonts + # cpAD Tools/HTMLTool/TOOL130 $gsosDir/System/Tools + # cpAD Tools/Hierarchic/Hierarchic $gsosDir/System/CDEvs + # cpAD Fonts/Shaston.16 $gsosDir/System/Fonts + + afpsync -v $gsosDir > /dev/null + fi + fi + + echo -n "ProTERM 3.1" + # get A2CLOUD disk and copy from there + if [[ -f $commDir/ProTERM/PROTERM ]]; then + echo " is already installed." + else + echo + mkdir -p $commDir/ProTERM + mkdir -p $commDir/ProTERM/.AppleDouble + cd /tmp/netboot + wget -qO A2CLOUD.HDV "${binaryURL}appleii/A2CLOUD.HDV" + cppo -s -ad A2CLOUD.HDV . &> /dev/null + cd A2CLOUD + mv *PT3* *PROTERM* $commDir/ProTERM + cd .AppleDouble + mv *PT3* *PROTERM* $commDir/ProTERM/.AppleDouble + afpsync -v $gsosDir > /dev/null + fi + + echo -n "Z-Link 12-15-91" + # get A2CLOUD disk and copy from there + if [[ -f $commDir/Z.Link/Z.LINK ]]; then + echo " is already installed." + else + echo + mkdir -p $commDir/Z.Link + mkdir -p $commDir/Z.Link/.AppleDouble + cd /tmp/netboot/A2CLOUD + mv Z.LINK $commDir/Z.Link + cd .AppleDouble + mv Z.LINK $commDir/Z.Link/.AppleDouble + afpsync -v $gsosDir > /dev/null + fi + + echo -n "ADTPro 2.0.1" + if [[ -f $commDir/ADTPro/ADTPRO ]]; then + echo " is already installed." + else + mkdir -p $commDir/ADTPro + mkdir -p $commDir/ADTPro/.AppleDouble + echo + cd /tmp/netboot/A2CLOUD + mv *ADTPRO* *VEDRIVE* *VSDRIVE* $commDir/ADTPro + cd .AppleDouble + mv *ADTPRO* *VEDRIVE* *VSDRIVE* $commDir/ADTPro/.AppleDouble + afpsync -v $gsosDir > /dev/null + fi + + fi + + # clean up + cd + + # rock and roll! + echo + + echo + if [[ $gsosInstall ]]; then + echo "GS/OS network boot (for registered user and Guest) and" + fi + echo "ProDOS 8 network boot (for Guest only) is now configured." + echo "See http://ivanx.com/a2server for info using it." + + fi + + REPLY= + if [[ -d $gsosDir/SYSTEM/SYSTEM.SETUP ]]; then + if [[ ! $autoAnswerYes ]]; then + if [[ ! -f $gsosDir/SYSTEM/SYSTEM.SETUP/ATALKIRQ ]]; then + echo + echo "Do you want to download the patch required for using" + echo -n "a Farallon LocalTalk-to-Ethernet bridge with GS/OS? " + read + else + echo + echo "A2SERVER: The Farallon bridge patch has already been installed." + fi + fi + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + # Farallon bridge patch for GS/OS courtesy of Geoff Body + echo "A2SERVER: Downloading Farallon bridge patch..." + wget -qO /tmp/FARALLON.PO "${binaryURL}appleii/FARALLON.B1.PO" &> /dev/null + cppo -s -ad /tmp/FARALLON.PO /ATALKPATCH/ATALKIRQ $gsosDir/SYSTEM/SYSTEM.SETUP &> /dev/null + echo + echo "A2SERVER: The Farallon bridge patch is installed." + echo + echo "Note: Farallon bridges can only be used in GS/OS (with this patch)" + echo "and Apple IIe computers. Apple IIgs computers which network boot" + echo "directly into ProDOS 8 will freeze after a few minutes." + fi + fi fi diff --git a/scripts/a2server-6-samba.txt b/scripts/a2server-6-samba.txt index 961879b..1f07e49 100755 --- a/scripts/a2server-6-samba.txt +++ b/scripts/a2server-6-samba.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # Set up A2SERVER to support Samba (Windows File Sharing) # this script can also be used if new shares are introduced @@ -8,79 +8,79 @@ if [[ ! $autoAnswerYes || -f /tmp/a2server-setupWindowsSharing ]]; then - if [[ ! $autoAnswerYes ]]; then - echo - echo -n "Should Windows computers be able to connect to A2SERVER? " - read - fi - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + if [[ ! $autoAnswerYes ]]; then + echo + echo -n "Should Windows computers be able to connect to A2SERVER? " + read + fi + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - echo "A2SERVER: Setting up Windows file sharing..." - sudo true + echo "A2SERVER: Setting up Windows file sharing..." + sudo true - sudo update-rc.d samba defaults &> /dev/null - [[ ! -f /etc/init.d/samba ]] && installSamba=1 + sudo update-rc.d samba defaults &> /dev/null + [[ ! -f /etc/init.d/samba ]] && installSamba=1 - if (( $installSamba )); then - if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then - # prepare for installing packages - sudo apt-get -y update - touch /tmp/a2server-packageReposUpdated - fi + if (( $installSamba )); then + if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then + # prepare for installing packages + sudo apt-get -y update + touch /tmp/a2server-packageReposUpdated + fi - # Dependency: samba for Windows/modern Macs - # FIXME: Figure out when smbpasswd moved and adjust this as necessary - sudo apt-get -y install samba - hash smbpasswd &> /dev/null || sudo apt-get -y install samba-common-bin - sudo apt-get clean - fi + # Dependency: samba for Windows/modern Macs + # FIXME: Figure out when smbpasswd moved and adjust this as necessary + sudo apt-get -y install samba + hash smbpasswd &> /dev/null || sudo apt-get -y install samba-common-bin + sudo apt-get clean + fi - sudo /etc/init.d/samba start &> /dev/null + sudo /etc/init.d/samba start &> /dev/null - workgroup=$(grep -o "^ workgroup = .*$" /etc/samba/smb.conf 2> /dev/null | cut -c 16-) - [[ $workgroup ]] || workgroup="WORKGROUP" - if [[ ! $autoAnswerYes ]]; then - echo - echo "Enter workgroup name (or press return for '${workgroup}'): " - read - [[ $REPLY ]] && workgroup=$REPLY - fi - sudo sed -i 's/^ workgroup = .*$/ workgroup = '$workgroup'/' /etc/samba/smb.conf 2> /dev/null - sudo sed -i 's/^# security = user/ security = user/' /etc/samba/smb.conf 2> /dev/null + workgroup=$(grep -o "^ workgroup = .*$" /etc/samba/smb.conf 2> /dev/null | cut -c 16-) + [[ $workgroup ]] || workgroup="WORKGROUP" + if [[ ! $autoAnswerYes ]]; then + echo + echo "Enter workgroup name (or press return for '${workgroup}'): " + read + [[ $REPLY ]] && workgroup=$REPLY + fi + sudo sed -i 's/^ workgroup = .*$/ workgroup = '$workgroup'/' /etc/samba/smb.conf 2> /dev/null + sudo sed -i 's/^# security = user/ security = user/' /etc/samba/smb.conf 2> /dev/null - # remove GSFILES if no longer serving it - if ! grep ^/srv/A2SERVER/GSFILES /usr/local/etc/netatalk/AppleVolumes.default; then - sudo sed -i ':a;N;$!ba;s#\n\[GSFILES\].*\[#\n[#' /etc/samba/smb.conf - sudo sed -i ':a;N;$!ba;s#\n\[GSFILES\].*$#\n#' /etc/samba/smb.conf - fi + # remove GSFILES if no longer serving it + if ! grep ^/srv/A2SERVER/GSFILES /usr/local/etc/netatalk/AppleVolumes.default; then + sudo sed -i ':a;N;$!ba;s#\n\[GSFILES\].*\[#\n[#' /etc/samba/smb.conf + sudo sed -i ':a;N;$!ba;s#\n\[GSFILES\].*$#\n#' /etc/samba/smb.conf + fi - grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | cut -d" " -f2 \ - | while read sharename; do - if [[ $(grep $sharename /etc/samba/smb.conf) ]]; then - echo "A2SERVER: $sharename is already set up for Windows file sharing." - else - echo "[$sharename]" | sudo tee -a /etc/samba/smb.conf > /dev/null - echo " path = /srv/A2SERVER/$sharename" | sudo tee -a /etc/samba/smb.conf > /dev/null - echo " browsable = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null - echo " guest ok = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null - echo " read only = no" | sudo tee -a /etc/samba/smb.conf > /dev/null - echo " create mask = 0666" | sudo tee -a /etc/samba/smb.conf > /dev/null - echo " force user = $USER" | sudo tee -a /etc/samba/smb.conf > /dev/null - echo "A2SERVER: $sharename has been set up for Windows file sharing." - fi - done + grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | cut -d" " -f2 \ + | while read sharename; do + if [[ $(grep $sharename /etc/samba/smb.conf) ]]; then + echo "A2SERVER: $sharename is already set up for Windows file sharing." + else + echo "[$sharename]" | sudo tee -a /etc/samba/smb.conf > /dev/null + echo " path = /srv/A2SERVER/$sharename" | sudo tee -a /etc/samba/smb.conf > /dev/null + echo " browsable = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null + echo " guest ok = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null + echo " read only = no" | sudo tee -a /etc/samba/smb.conf > /dev/null + echo " create mask = 0666" | sudo tee -a /etc/samba/smb.conf > /dev/null + echo " force user = $USER" | sudo tee -a /etc/samba/smb.conf > /dev/null + echo "A2SERVER: $sharename has been set up for Windows file sharing." + fi + done - echo - echo "A2SERVER: Setting Windows file sharing password to 'apple2'." - echo -e 'apple2\napple2' | sudo smbpasswd -s -a $USER + echo + echo "A2SERVER: Setting Windows file sharing password to 'apple2'." + echo -e 'apple2\napple2' | sudo smbpasswd -s -a $USER - echo - echo "A2SERVER: Windows file sharing is now running." - else - sudo /etc/init.d/samba stop &> /dev/null - sudo update-rc.d -f samba remove &> /dev/null - echo "A2SERVER: Windows file sharing has been turned off." - fi + echo + echo "A2SERVER: Windows file sharing is now running." + else + sudo /etc/init.d/samba stop &> /dev/null + sudo update-rc.d -f samba remove &> /dev/null + echo "A2SERVER: Windows file sharing has been turned off." + fi - echo + echo fi diff --git a/scripts/a2server-7-console.txt b/scripts/a2server-7-console.txt index 25e72b2..ad33d18 100755 --- a/scripts/a2server-7-console.txt +++ b/scripts/a2server-7-console.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # This script helps when running on the Linux console within a VirtualBox VM. @@ -17,11 +17,11 @@ isDebian= b_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ ( -f /etc/debian_version ) && ( $(cut -d . -f 1 < /etc/debian_version) -ge "7" ) ]] && isDebian=1 if [[ $isDebian ]]; then - if { lspci 2> /dev/null | grep -q VirtualBox; }; then - echo "A2SERVER: Disabling VirtualBox console screen blanking..." - sudo sed -i 's/^BLANK_DPMS=off/BLANK_DPMS=on/' /etc/kbd/config - sudo sed -i 's/^BLANK_TIME=[^0].$/BLANK_TIME=0/' /etc/kbd/config - sudo /etc/init.d/kbd restart &> /dev/null - sudo /etc/init.d/console-setup restart &> /dev/null - fi + if { lspci 2> /dev/null | grep -q VirtualBox; }; then + echo "A2SERVER: Disabling VirtualBox console screen blanking..." + sudo sed -i 's/^BLANK_DPMS=off/BLANK_DPMS=on/' /etc/kbd/config + sudo sed -i 's/^BLANK_TIME=[^0].$/BLANK_TIME=0/' /etc/kbd/config + sudo /etc/init.d/kbd restart &> /dev/null + sudo /etc/init.d/console-setup restart &> /dev/null + fi fi diff --git a/scripts/raspbian-update.txt b/scripts/raspbian-update.txt index cf62913..fe62708 100644 --- a/scripts/raspbian-update.txt +++ b/scripts/raspbian-update.txt @@ -1,4 +1,5 @@ #!/bin/bash +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # raspbian-update # updates Raspbian to latest version, including NOOBS if installed @@ -6,8 +7,8 @@ [[ -f /usr/bin/raspi-config ]] && isRpi=1 || isRpi= if [[ ! $isRpi ]]; then - echo "This ain't a Raspberry Pi." - [[ $0 == "-bash" ]] && return 1 || exit 1 + echo "This ain't a Raspberry Pi." + [[ $0 == "-bash" ]] && return 1 || exit 1 fi skipRepoUpdate= @@ -15,30 +16,30 @@ autoYes= updateA2Cloud= updateA2Server= while [[ $1 ]]; do - if [[ $1 == "-r" ]]; then - shift - skipRepoUpdate="-r" - elif [[ $1 == "-y" ]]; then - shift - autoYes="-y" - elif [[ $1 == "-n" ]]; then - shift - noobsOnly="-n" - elif [[ $1 == "a2cloud" ]]; then - shift - updateA2Cloud=1 - elif [[ $1 == "a2server" ]]; then - shift - updateA2Server=1 - elif [[ $1 ]]; then - echo "options:" - echo "-y: auto-answer yes to all prompts and don't prompt for restart" - echo "-r: don't update package repositories" - echo "-n: update NOOBS only; don't update Raspbian" - echo "a2cloud : update A2CLOUD when complete" - echo "a2server: update A2SERVER when complete" - [[ $0 == "-bash" ]] && return 1 || exit 1 - fi + if [[ $1 == "-r" ]]; then + shift + skipRepoUpdate="-r" + elif [[ $1 == "-y" ]]; then + shift + autoYes="-y" + elif [[ $1 == "-n" ]]; then + shift + noobsOnly="-n" + elif [[ $1 == "a2cloud" ]]; then + shift + updateA2Cloud=1 + elif [[ $1 == "a2server" ]]; then + shift + updateA2Server=1 + elif [[ $1 ]]; then + echo "options:" + echo "-y: auto-answer yes to all prompts and don't prompt for restart" + echo "-r: don't update package repositories" + echo "-n: update NOOBS only; don't update Raspbian" + echo "a2cloud : update A2CLOUD when complete" + echo "a2server: update A2SERVER when complete" + [[ $0 == "-bash" ]] && return 1 || exit 1 + fi done noobs= @@ -49,138 +50,138 @@ if [[ \ ${partitions[2]:0:14} == "/dev/mmcblk0p3" && ${partitions[2]:57:2} == "83" && ${partitions[3]:0:14} == "/dev/mmcblk0p5" && ${partitions[3]:57:2} == " c" && ${partitions[4]:0:14} == "/dev/mmcblk0p6" && ${partitions[4]:57:2} == "83" ]]; then - noobs=" and the NOOBS install manager" + noobs=" and the NOOBS install manager" fi if [[ ! $autoYes ]]; then - echo - echo "You are about to update your SD card to the latest version of the" - echo "Raspbian operating system${noobs}." - echo - echo "This may take an hour or more, and will require restarting when complete." - echo "You might want a backup before continuing in case it doesn't go as planned." - echo - echo -n "Update Raspbian? " - read - if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then - [[ $0 == "-bash" ]] && return 2 || exit 2 - fi + echo + echo "You are about to update your SD card to the latest version of the" + echo "Raspbian operating system${noobs}." + echo + echo "This may take an hour or more, and will require restarting when complete." + echo "You might want a backup before continuing in case it doesn't go as planned." + echo + echo -n "Update Raspbian? " + read + if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then + [[ $0 == "-bash" ]] && return 2 || exit 2 + fi fi origDir="$PWD" cd /tmp if [[ ! $skipRepoUpdate ]]; then - echo "Updating package repositories..." - sudo apt-get -y update > /dev/null + echo "Updating package repositories..." + sudo apt-get -y update > /dev/null else - echo "Not updating package repositories..." - echo + echo "Not updating package repositories..." + echo fi if [[ ! $noobsOnly ]]; then - { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null - freeSpace=$(df / | tail -1 | awk '{ print $4 }') - if (( $freeSpace < 400000 )); then - if dpkg -l | grep -q wolfram-engine; then - if [[ ! $autoYes ]]; then - echo "In order to create enough space on your SD card to upgrade," - echo "the Wolfram Language and Mathematica software packages must be removed." - echo "If you don't know what these are, this won't affect you at all." - echo - echo -n "Remove Wolfram software? " - read - if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then - [[ $0 == "-bash" ]] && return 2 || exit 2 - fi - sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null - sudo apt-get -y purge wolfram-engine - else - echo "Removing Wolfram software due to space constraints..." - sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null - sudo apt-get -y purge wolfram-engine - fi - else - echo "You don't have enough free space on your SD card to upgrade." - echo "Sorry, man. Delete some stuff or get a bigger card." - [[ $0 == "-bash" ]] && return 1 || exit 1 - fi - fi + { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null + freeSpace=$(df / | tail -1 | awk '{ print $4 }') + if (( $freeSpace < 400000 )); then + if dpkg -l | grep -q wolfram-engine; then + if [[ ! $autoYes ]]; then + echo "In order to create enough space on your SD card to upgrade," + echo "the Wolfram Language and Mathematica software packages must be removed." + echo "If you don't know what these are, this won't affect you at all." + echo + echo -n "Remove Wolfram software? " + read + if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then + [[ $0 == "-bash" ]] && return 2 || exit 2 + fi + sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null + sudo apt-get -y purge wolfram-engine + else + echo "Removing Wolfram software due to space constraints..." + sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null + sudo apt-get -y purge wolfram-engine + fi + else + echo "You don't have enough free space on your SD card to upgrade." + echo "Sorry, man. Delete some stuff or get a bigger card." + [[ $0 == "-bash" ]] && return 1 || exit 1 + fi + fi - { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null - dpkg -l | grep -q a2pi && sudo apt-get -y --force-yes install a2pi - dpkg -l | grep -q apple2user && sudo apt-get -y --force-yes install apple2user gsport - if dpkg -l | grep -q wolfram-engine; then - sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null - if [[ $freeSpace -lt 750000 && $(apt-get -s install wolfram-engine | grep upgraded) ]]; then - sudo apt-get -y purge wolfram-engine - { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null - fi - sudo apt-get -y install wolfram-engine - { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null - fi - sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade - { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null - sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade - { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null - sudo apt-get -y install raspberrypi-ui-mods - { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null + { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null + dpkg -l | grep -q a2pi && sudo apt-get -y --force-yes install a2pi + dpkg -l | grep -q apple2user && sudo apt-get -y --force-yes install apple2user gsport + if dpkg -l | grep -q wolfram-engine; then + sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null + if [[ $freeSpace -lt 750000 && $(apt-get -s install wolfram-engine | grep upgraded) ]]; then + sudo apt-get -y purge wolfram-engine + { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null + fi + sudo apt-get -y install wolfram-engine + { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null + fi + sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade + { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null + sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade + { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null + sudo apt-get -y install raspberrypi-ui-mods + { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null fi if [[ $noobs ]]; then - echo "Updating NOOBS..." + echo "Updating NOOBS..." - # update Partition 3 - mkdir -p /tmp/p3 - sudo mount /dev/mmcblk0p3 /tmp/p3 - sudo rm -rf /tmp/p3/os/* 2> /dev/null - if grep -q 'Raspple II' /tmp/p3/installed_os.json; then - echo "Downloading Raspple II lite..." - noobsUrl="ivanx.com/rasppleii/files/RasppleII_lite.zip" - noobsOSurl="ivanx.com/rasppleii/noobs-os" - distDir="Raspple_II" - sudo mkdir -p /tmp/p3/os/$distDir - sudo sed -i 's:/Raspbian:/Raspple_II:' /tmp/p3/installed_os.json - sudo wget -qO /tmp/p3/icon.png $noobsOSurl/Raspple_II.png - { wget -qO- $noobsOSurl/slidesAB.tar | sudo tar -C /tmp/p3/os/$distDir -x; } &> /dev/null - else - echo "Downloading NOOBS lite..." - noobsRoot="downloads.raspberrypi.org/NOOBS_lite/images/" - noobsDir=$(wget -qO- $noobsRoot | grep '^ /dev/null - fi - sudo rm -rf /tmp/p3/cache 2> /dev/null - releaseDate=$(wget -qO- $noobsOSurl/os.json | grep 'release_date' | cut -f 4 -d '"') - sudo sed -i 's/"release_date".*$/"release_date" : "'$releaseDate'"/' /tmp/p3/installed_os.json - sudo sed -i 's/keyboard_layout=gb/keyboard_layout=us/' /tmp/p3/noobs.conf - sudo sed -i 's:/mnt/:/settings/:' /tmp/p3/installed_os.json - sudo sed -i 's@"icon".*,@"icon" : "/settings/os/'$distDir'/icon.png",@' /tmp/p3/installed_os.json - sudo cp /tmp/p3/icon.png /tmp/p3/os/$distDir - sudo wget -qO /tmp/p3/os/$distDir/os.json $noobsOSurl/os.json - sudo wget -qO /tmp/p3/os/$distDir/partition_setup.sh $noobsOSurl/partition_setup.sh - sudo wget -qO /tmp/p3/os/$distDir/partitions.json $noobsOSurl/partitions.json - sudo umount /tmp/p3 - rmdir /tmp/p3 + # update Partition 3 + mkdir -p /tmp/p3 + sudo mount /dev/mmcblk0p3 /tmp/p3 + sudo rm -rf /tmp/p3/os/* 2> /dev/null + if grep -q 'Raspple II' /tmp/p3/installed_os.json; then + echo "Downloading Raspple II lite..." + noobsUrl="ivanx.com/rasppleii/files/RasppleII_lite.zip" + noobsOSurl="ivanx.com/rasppleii/noobs-os" + distDir="Raspple_II" + sudo mkdir -p /tmp/p3/os/$distDir + sudo sed -i 's:/Raspbian:/Raspple_II:' /tmp/p3/installed_os.json + sudo wget -qO /tmp/p3/icon.png $noobsOSurl/Raspple_II.png + { wget -qO- $noobsOSurl/slidesAB.tar | sudo tar -C /tmp/p3/os/$distDir -x; } &> /dev/null + else + echo "Downloading NOOBS lite..." + noobsRoot="downloads.raspberrypi.org/NOOBS_lite/images/" + noobsDir=$(wget -qO- $noobsRoot | grep '^ /dev/null + fi + sudo rm -rf /tmp/p3/cache 2> /dev/null + releaseDate=$(wget -qO- $noobsOSurl/os.json | grep 'release_date' | cut -f 4 -d '"') + sudo sed -i 's/"release_date".*$/"release_date" : "'$releaseDate'"/' /tmp/p3/installed_os.json + sudo sed -i 's/keyboard_layout=gb/keyboard_layout=us/' /tmp/p3/noobs.conf + sudo sed -i 's:/mnt/:/settings/:' /tmp/p3/installed_os.json + sudo sed -i 's@"icon".*,@"icon" : "/settings/os/'$distDir'/icon.png",@' /tmp/p3/installed_os.json + sudo cp /tmp/p3/icon.png /tmp/p3/os/$distDir + sudo wget -qO /tmp/p3/os/$distDir/os.json $noobsOSurl/os.json + sudo wget -qO /tmp/p3/os/$distDir/partition_setup.sh $noobsOSurl/partition_setup.sh + sudo wget -qO /tmp/p3/os/$distDir/partitions.json $noobsOSurl/partitions.json + sudo umount /tmp/p3 + rmdir /tmp/p3 - # update Partition 1 - mkdir -p /tmp/p1 - sudo mount /dev/mmcblk0p1 /tmp/p1 - wget -qO /tmp/noobs_lite.zip $noobsUrl - sudo rm -rf /tmp/p1/* - sudo unzip -d /tmp/p1 /tmp/noobs_lite.zip - sudo sed -i 's/^runinstaller //' /tmp/p1/recovery.cmdline - sudo sed -i 's/silentinstall//' /tmp/p1/recovery.cmdline - grep -q 'keyboard=us' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 keyboard=us/' /tmp/p1/recovery.cmdline - grep -q 'disablesafemode' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 disablesafemode/' /tmp/p1/recovery.cmdline - sudo umount /tmp/p1 - rmdir /tmp/p1 + # update Partition 1 + mkdir -p /tmp/p1 + sudo mount /dev/mmcblk0p1 /tmp/p1 + wget -qO /tmp/noobs_lite.zip $noobsUrl + sudo rm -rf /tmp/p1/* + sudo unzip -d /tmp/p1 /tmp/noobs_lite.zip + sudo sed -i 's/^runinstaller //' /tmp/p1/recovery.cmdline + sudo sed -i 's/silentinstall//' /tmp/p1/recovery.cmdline + grep -q 'keyboard=us' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 keyboard=us/' /tmp/p1/recovery.cmdline + grep -q 'disablesafemode' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 disablesafemode/' /tmp/p1/recovery.cmdline + sudo umount /tmp/p1 + rmdir /tmp/p1 - sudo sed -i 's/\(Raspple II release.*[^u]$\)/\1u/' /etc/issue + sudo sed -i 's/\(Raspple II release.*[^u]$\)/\1u/' /etc/issue fi echo @@ -190,44 +191,44 @@ echo cd /tmp if [[ $updateA2Cloud ]]; then - wget -qO /tmp/a2cloud-setup ivanx.com/a2cloud/setup/ - source /tmp/a2cloud-setup -y -r noSetGroups - if acmd -g /usr/share/gsport/disks/GSport\ Internet\ Starter\ Kit.2mg SYSTEM/FONTS/SIS.4.10 &> /dev/null; then - wget -qO /tmp/ua2.txt ivanx.com/rasppleii/files/a/ua2.txt - source /tmp/ua2.txt - fi - echo - echo "*** A2CLOUD update completed. ***" - echo + wget -qO /tmp/a2cloud-setup ivanx.com/a2cloud/setup/ + source /tmp/a2cloud-setup -y -r noSetGroups + if acmd -g /usr/share/gsport/disks/GSport\ Internet\ Starter\ Kit.2mg SYSTEM/FONTS/SIS.4.10 &> /dev/null; then + wget -qO /tmp/ua2.txt ivanx.com/rasppleii/files/a/ua2.txt + source /tmp/ua2.txt + fi + echo + echo "*** A2CLOUD update completed. ***" + echo fi cd /tmp if [[ $updateA2Server ]]; then - wget -q -O /tmp/a2server-setup ivanx.com/a2server/setup/ - if ps aux | grep -q [s]mbd; then - source /tmp/a2server-setup -y -r -w - else - source /tmp/a2server-setup -y -r - fi - echo - echo "*** A2SERVER update completed. ***" - echo + wget -q -O /tmp/a2server-setup ivanx.com/a2server/setup/ + if ps aux | grep -q [s]mbd; then + source /tmp/a2server-setup -y -r -w + else + source /tmp/a2server-setup -y -r + fi + echo + echo "*** A2SERVER update completed. ***" + echo fi cd "$origDir" if [[ ! $autoYes ]]; then - echo - echo - echo "Your system has been updated and needs to reboot to use its new software." - echo - echo -n "Reboot now (recommended)? " - read - if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - sudo shutdown -r now - fi + echo + echo + echo "Your system has been updated and needs to reboot to use its new software." + echo + echo -n "Reboot now (recommended)? " + read + if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + sudo shutdown -r now + fi else - echo "*** raspbian-update completed. ***" - sudo shutdown -r now + echo "*** raspbian-update completed. ***" + sudo shutdown -r now fi diff --git a/scripts/tools/a2server-aliases.txt b/scripts/tools/a2server-aliases.txt index 5c1317e..cdf984a 100755 --- a/scripts/tools/a2server-aliases.txt +++ b/scripts/tools/a2server-aliases.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: alias a2server-help="more /usr/local/etc/a2server-help.txt" alias a2server-setup='wget -q -O /tmp/a2server-setup ${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current/}setup/index.txt || { echo "Can'"'"'t download A2SERVER setup scripts. Do you has internet?"; false; } && source /tmp/a2server-setup' diff --git a/scripts/tools/a2serverrc.txt b/scripts/tools/a2serverrc.txt index 9405070..0017a07 100755 --- a/scripts/tools/a2serverrc.txt +++ b/scripts/tools/a2serverrc.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: export A2SERVER_SCRIPT_URL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current/}" export A2SERVER_BINARY_URL="${A2SERVER_BINARY_URL:-http://ivanx.com/a2server/files/}" diff --git a/scripts/tools/afpsync.txt b/scripts/tools/afpsync.txt index 3462a68..9082b4b 100755 --- a/scripts/tools/afpsync.txt +++ b/scripts/tools/afpsync.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # afpsync: updates .AppleDouble components of files on shared volumes @@ -15,102 +15,102 @@ # /usr/local/etc/netatalk/AppleVolumes.default are synced. processPath () { - if [[ ! -d $sharepath ]]; then - echo "$sharepath does not exist." - else - volinfo="$sharepath/.AppleDesktop/.volinfo" - if [[ ! -f $volinfo ]]; then - if [[ ! $force ]]; then - echo "Cannot update AppleDouble files for volume $sharepath," - echo "because its .volinfo file does not exist. To create it, log" - echo "into the volume from an Apple II or Mac client computer," - echo "or use \"afpsync -v\"." - else - if (( $1 )); then - mkvolinfo -f -c $sharepath - else - mkvolinfo -f $sharepath - fi - $0 $sharepath - fi - else - IFS='' - result=$(sudo dbd -r $sharepath | grep encoding) - f=$(wc -l <<< $result) - [[ $(wc -w <<< $result) == 0 ]] && f=0 - [[ $f -eq 1 && $(grep AppleDesktop <<< "$result") && $(grep MTOULOWER $sharepath/.AppleDesktop/.volinfo) ]] && (( f-- )) - if (( f == 0 )); then - echo "AppleDouble files have been updated for volume $sharepath." - else - [[ ! $renameLower ]] && echo "Could not update all files on volume $sharepath." - if [[ $showerrors ]]; then - echo $result \ - | while read LINE; do - [[ ! $(echo $LINE | grep APPLEDESKTOP) ]] && echo $LINE - done - elif [[ $renameLower ]]; then - echo $result \ - | while read LINE; do - if [[ ! $(echo $LINE | grep APPLEDESKTOP) ]]; then - filepath=$(echo $LINE | sed "s/^Bad\ encoding\ for\ '//" | sed s/\'//) - filename=${filepath##*/} - filedir=${filepath%/*} - mv $filepath $filedir/${filename^^} - echo "Renamed $filedir/${filename^^}." - fi - done - $0 $sharepath - else - echo "Use afpsync -e to see error details." - fi - fi - unset IFS - fi - fi + if [[ ! -d $sharepath ]]; then + echo "$sharepath does not exist." + else + volinfo="$sharepath/.AppleDesktop/.volinfo" + if [[ ! -f $volinfo ]]; then + if [[ ! $force ]]; then + echo "Cannot update AppleDouble files for volume $sharepath," + echo "because its .volinfo file does not exist. To create it, log" + echo "into the volume from an Apple II or Mac client computer," + echo "or use \"afpsync -v\"." + else + if (( $1 )); then + mkvolinfo -f -c $sharepath + else + mkvolinfo -f $sharepath + fi + $0 $sharepath + fi + else + IFS='' + result=$(sudo dbd -r $sharepath | grep encoding) + f=$(wc -l <<< $result) + [[ $(wc -w <<< $result) == 0 ]] && f=0 + [[ $f -eq 1 && $(grep AppleDesktop <<< "$result") && $(grep MTOULOWER $sharepath/.AppleDesktop/.volinfo) ]] && (( f-- )) + if (( f == 0 )); then + echo "AppleDouble files have been updated for volume $sharepath." + else + [[ ! $renameLower ]] && echo "Could not update all files on volume $sharepath." + if [[ $showerrors ]]; then + echo $result \ + | while read LINE; do + [[ ! $(echo $LINE | grep APPLEDESKTOP) ]] && echo $LINE + done + elif [[ $renameLower ]]; then + echo $result \ + | while read LINE; do + if [[ ! $(echo $LINE | grep APPLEDESKTOP) ]]; then + filepath=$(echo $LINE | sed "s/^Bad\ encoding\ for\ '//" | sed s/\'//) + filename=${filepath##*/} + filedir=${filepath%/*} + mv $filepath $filedir/${filename^^} + echo "Renamed $filedir/${filename^^}." + fi + done + $0 $sharepath + else + echo "Use afpsync -e to see error details." + fi + fi + unset IFS + fi + fi } while [[ $1 == "-r" || $1 == "-e" || $1 = "-v" ]]; do - if [[ $1 == "-v" ]]; then - force=1 - shift - fi + if [[ $1 == "-v" ]]; then + force=1 + shift + fi - if [[ $1 == "-e" ]]; then - showerrors=1 - shift - fi + if [[ $1 == "-e" ]]; then + showerrors=1 + shift + fi - if [[ $1 == "-r" ]]; then - renameLower=1 - shift - fi + if [[ $1 == "-r" ]]; then + renameLower=1 + shift + fi done if [[ ${1:0:1} == "-" ]]; then - echo "Usage: afpsync [-e|-r] [-v] [shared volume path]" - echo - echo "-e: show error details" - echo "-r: rename lowercase filenames to uppercase" - echo "-v: create .volinfo file if none exists" - echo "If no directory is specified, all found in" - echo " /usr/local/etc/netatalk/AppleVolumes.default are processed." - echo + echo "Usage: afpsync [-e|-r] [-v] [shared volume path]" + echo + echo "-e: show error details" + echo "-r: rename lowercase filenames to uppercase" + echo "-v: create .volinfo file if none exists" + echo "If no directory is specified, all found in" + echo " /usr/local/etc/netatalk/AppleVolumes.default are processed." + echo else - sudo true - if [[ $1 ]]; then - sharepath=$(readlink -m $1) - # behavior change in 1.3.0: now defaults to mixed case - # on a volume when specifying a folder and -v - # (as opposed to defaulting to casefold:toupper previously) - processPath 1 - else - grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | \ - while read line; do - [[ $(echo $line | grep toupper) ]]; nocasefold=$? - sharepath=$(echo $line | cut -d" " -f1) - processPath nocasefold - done - fi + sudo true + if [[ $1 ]]; then + sharepath=$(readlink -m $1) + # behavior change in 1.3.0: now defaults to mixed case + # on a volume when specifying a folder and -v + # (as opposed to defaulting to casefold:toupper previously) + processPath 1 + else + grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | \ + while read line; do + [[ $(echo $line | grep toupper) ]]; nocasefold=$? + sharepath=$(echo $line | cut -d" " -f1) + processPath nocasefold + done + fi fi diff --git a/scripts/tools/afptype.txt b/scripts/tools/afptype.txt index 66cf3f9..7b0a78d 100755 --- a/scripts/tools/afptype.txt +++ b/scripts/tools/afptype.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # 2-25-11: tested on 10.6.5 and Ubuntu 10.10. Final. @@ -56,12 +56,12 @@ decToHex () { # arg: decimal value from 0-255 # out: two-digit hex value from 00-FF #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg - [[ $1 ]] || return 11 - [[ $2 ]] && return 8 - [[ ( $(printf %d "$1" 2> /dev/null) == $1 ) \ - && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 - # args are valid - printf %02X "$1" + [[ $1 ]] || return 11 + [[ $2 ]] && return 8 + [[ ( $(printf %d "$1" 2> /dev/null) == $1 ) \ + && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 + # args are valid + printf %02X "$1" } hexToDec () { @@ -69,13 +69,13 @@ hexToDec () { # arg: two-digit hex value from 00-FF # out: decimal value #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg - [[ $1 ]] || return 11 - [[ $2 ]] && return 8 - [[ ${#1} -eq 2 ]] || return 21 - [[ $(printf %02X "0x$1" 2> /dev/null) == \ - $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21 - # args are valid - printf %d "0x$1" + [[ $1 ]] || return 11 + [[ $2 ]] && return 8 + [[ ${#1} -eq 2 ]] || return 21 + [[ $(printf %02X "0x$1" 2> /dev/null) == \ + $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21 + # args are valid + printf %d "0x$1" } charToDec () { @@ -85,15 +85,15 @@ charToDec () { # out: decimal value from 0-255 #exit: 8=extraneous arg, 9=invalid stdin, # 11=missing stdin/arg, 21=invalid arg - [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } - [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } - # arg/stdin is potentially valid (additional check below) - charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" - [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) - # above line verifies that arg/stdin is valid - [[ ${#charX} -ne 2 ]] && { echo -n 0; return 0; } - echo -n "${charX:0:1}" | od -t u1 | \ - head -1 | sed 's/[0\ ]*//' | tr -d ' \n' + [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } + [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } + # arg/stdin is potentially valid (additional check below) + charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" + [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) + # above line verifies that arg/stdin is valid + [[ ${#charX} -ne 2 ]] && { echo -n 0; return 0; } + echo -n "${charX:0:1}" | od -t u1 | \ + head -1 | sed 's/[0\ ]*//' | tr -d ' \n' } charToHex () { @@ -103,15 +103,15 @@ charToHex () { # out: decimal value from 0-255 #exit: 8=extraneous arg, 9=invalid stdin, # 11=missing stdin/arg, 21=invalid arg - [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } - [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } - # arg/stdin is potentially valid (additional check below) - charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" - [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) - # above line verifies that stdin/arg is valid - [[ ${#charX} -ne 2 ]] && { echo -n "00"; return 0; } - printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \ - head -1 | sed 's/[0\ ]*//' | tr -d ' \n') + [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } + [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } + # arg/stdin is potentially valid (additional check below) + charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" + [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) + # above line verifies that stdin/arg is valid + [[ ${#charX} -ne 2 ]] && { echo -n "00"; return 0; } + printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \ + head -1 | sed 's/[0\ ]*//' | tr -d ' \n') } decToChar () { @@ -119,12 +119,12 @@ decToChar () { # arg: decimal number from 0-255 # out: one character #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg - [[ $1 ]] || return 11 - [[ $2 ]] && return 8 - [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ - && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 - # args are valid - echo -n -e "\x$(printf %02X "$1")" + [[ $1 ]] || return 11 + [[ $2 ]] && return 8 + [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ + && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 + # args are valid + echo -n -e "\x$(printf %02X "$1")" } hexToChar () { @@ -132,13 +132,13 @@ hexToChar () { # arg: two-digit hexadecimal number from 00-FF # out: one character #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg - [[ $1 ]] || return 11 - [[ $2 ]] && return 8 - [[ ${#1} -eq 2 ]] || return 21 - [[ $(printf %02X "0x$1" 2> /dev/null) == \ - $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21 - # args are valid - echo -n -e "\x$1" + [[ $1 ]] || return 11 + [[ $2 ]] && return 8 + [[ ${#1} -eq 2 ]] || return 21 + [[ $(printf %02X "0x$1" 2> /dev/null) == \ + $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21 + # args are valid + echo -n -e "\x$1" } readchars () { @@ -149,16 +149,16 @@ readchars () { # out: sequence of characters # exit: 8=extraneous arg, 11=missing arg1, # 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 - [[ $1 ]] || return 11 - [[ $4 ]] && return 8 - [[ -f $1 ]] || return 21 - [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ - && ( $2 -ge 0 ) ]] || return 22; } - [[ $3 ]] && { [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \ - && ( $3 -ge 0 ) ]] || return 23; } - # args are valid - dd if="$1" bs=1 skip=$(($2)) $([[ $3 ]] && echo -n "count=$3") \ - 2> /dev/null + [[ $1 ]] || return 11 + [[ $4 ]] && return 8 + [[ -f $1 ]] || return 21 + [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ + && ( $2 -ge 0 ) ]] || return 22; } + [[ $3 ]] && { [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \ + && ( $3 -ge 0 ) ]] || return 23; } + # args are valid + dd if="$1" bs=1 skip=$(($2)) $([[ $3 ]] && echo -n "count=$3") \ + 2> /dev/null } readcharDec () { @@ -168,17 +168,17 @@ readcharDec () { # out: decimal value from 0-255 # exit: 8=extraneous arg, 11=missing arg1, # 21=invalid arg1, 22=invalid arg2 - [[ $1 ]] || return 11 - [[ $3 ]] && return 8 - [[ -f $1 ]] || return 21 - [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ - && ( $2 -ge 0 ) ]] || return 22; } - # args are valid - charX="$(dd if="$1" bs=1 skip=$(($2)) \ - count=1 2> /dev/null; echo -n X)" - [[ ${#charX} -gt 1 ]] || { echo -n 0; return 0; } - echo -n "${charX:0:1}" | od -t u1 | \ - head -1 | sed 's/[0\ ]*//' | tr -d ' \n' + [[ $1 ]] || return 11 + [[ $3 ]] && return 8 + [[ -f $1 ]] || return 21 + [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ + && ( $2 -ge 0 ) ]] || return 22; } + # args are valid + charX="$(dd if="$1" bs=1 skip=$(($2)) \ + count=1 2> /dev/null; echo -n X)" + [[ ${#charX} -gt 1 ]] || { echo -n 0; return 0; } + echo -n "${charX:0:1}" | od -t u1 | \ + head -1 | sed 's/[0\ ]*//' | tr -d ' \n' } readcharHex () { @@ -188,17 +188,17 @@ readcharHex () { # out: two-digit hex value from 00-FF # exit: 8=extraneous arg, 11=missing arg1, # 21=invalid arg1, 22=invalid arg2 - [[ $1 ]] || return 11 - [[ $3 ]] && return 8 - [[ -f $1 ]] || return 21 - [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ - && ( $2 -ge 0 ) ]] || return 22; } - # args are valid - charX="$(dd if="$1" bs=1 skip=$(($2)) \ - count=1 2> /dev/null; echo -n X)" - [[ ${#charX} -gt 1 ]] || { echo -n "00"; return 0; } - printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \ - head -1 | sed 's/[0\ ]*//' | tr -d ' \n') + [[ $1 ]] || return 11 + [[ $3 ]] && return 8 + [[ -f $1 ]] || return 21 + [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ + && ( $2 -ge 0 ) ]] || return 22; } + # args are valid + charX="$(dd if="$1" bs=1 skip=$(($2)) \ + count=1 2> /dev/null; echo -n X)" + [[ ${#charX} -gt 1 ]] || { echo -n "00"; return 0; } + printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \ + head -1 | sed 's/[0\ ]*//' | tr -d ' \n') } ### 2-15-11 above tested on OS X and Linux @@ -212,18 +212,18 @@ writechars () { # out: nothing # exit: 8=extraneous arg, 11=missing arg1, # 13=missing stdin/arg3, 22=invalid arg2 - [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } - [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ - ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } - [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } - [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } - # args are valid - if [[ -t 0 ]]; then - echo -n "$3" | \ - dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null - else - dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null - fi + [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } + [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ + ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } + [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } + [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } + # args are valid + if [[ -t 0 ]]; then + echo -n "$3" | \ + dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null + else + dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null + fi } writecharDec () { @@ -234,15 +234,15 @@ writecharDec () { # exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2, # 13=missing arg3, 22=invalid arg2, 23=invalid arg3 # out: nothing - [[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13 - [[ $4 ]] && return 8 - [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ - && ( $2 -ge 0 ) ]] || return 22 - [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \ - && ( $3 -ge 0 ) && ( $3 -lt 255 ) ]] || return 23 - # args are valid - echo -n -e "\x$(printf %02X "$3")" | \ - dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null + [[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13 + [[ $4 ]] && return 8 + [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ + && ( $2 -ge 0 ) ]] || return 22 + [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \ + && ( $3 -ge 0 ) && ( $3 -lt 255 ) ]] || return 23 + # args are valid + echo -n -e "\x$(printf %02X "$3")" | \ + dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null } writecharHex () { @@ -253,23 +253,23 @@ writecharHex () { # out: nothing # exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2, # 13=missing arg3, 22=invalid arg2, 23=invalid arg3 - [[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13 - [[ $4 ]] && return 8 - [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ - && ( $2 -ge 0 ) ]] || return 22 - [[ $(printf %02X "0x$3" 2> /dev/null) == \ - $(echo -n "$3" | tr [a-z] [A-Z]) ]] || return 23 - # args are valid - echo -n -e "\x$3" | \ - dd of="$1" bs=1 seek=$2 conv=notrunc 2> /dev/null + [[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13 + [[ $4 ]] && return 8 + [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ + && ( $2 -ge 0 ) ]] || return 22 + [[ $(printf %02X "0x$3" 2> /dev/null) == \ + $(echo -n "$3" | tr [a-z] [A-Z]) ]] || return 23 + # args are valid + echo -n -e "\x$3" | \ + dd of="$1" bs=1 seek=$2 conv=notrunc 2> /dev/null } # --- afptype is below this line isHexByte () { - [[ $(printf %02X "0x$1" 2> /dev/null) == \ - $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 1 + [[ $(printf %02X "0x$1" 2> /dev/null) == \ + $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 1 } # support 00 and 0A as filetype chars? @@ -278,27 +278,27 @@ debug=1 ptypes="04:TXT 06:BIN B3:S16 E0:SHK F9:P16 FA:INT FC:BAS FF:SYS" quit () { - if [[ $2 && $debug ]]; then - echo "$1" "$2" - else - echo -e "Error: $1" - fi - exit_usage + if [[ $2 && $debug ]]; then + echo "$1" "$2" + else + echo -e "Error: $1" + fi + exit_usage } exit_usage () { - echo "Usage:" - echo - echo "show types: afptype filename" - echo "set Mac OS: afptype [-t 'type'] [-c 'creator'] [-q] filename" - echo "set ProDOS: afptype [-p type] [-a auxtype] [-q] filename" - echo "Mac OS type or creator must be four characters; use \x plus" - echo " two hex digits for untypeables (note: use '\xZZ' for 00)." - echo "ProDOS type should be two hex digits, and auxtype should be four;" - echo " type can alternatively be BAS, BIN, INT, P16, S16, SHK, SYS, TXT." - echo "-q skips recheck of file (show types) after setting" - echo - exit 1 + echo "Usage:" + echo + echo "show types: afptype filename" + echo "set Mac OS: afptype [-t 'type'] [-c 'creator'] [-q] filename" + echo "set ProDOS: afptype [-p type] [-a auxtype] [-q] filename" + echo "Mac OS type or creator must be four characters; use \x plus" + echo " two hex digits for untypeables (note: use '\xZZ' for 00)." + echo "ProDOS type should be two hex digits, and auxtype should be four;" + echo " type can alternatively be BAS, BIN, INT, P16, S16, SHK, SYS, TXT." + echo "-q skips recheck of file (show types) after setting" + echo + exit 1 } lookupPdosType () { @@ -306,65 +306,65 @@ lookupPdosType () { # arg: three-character code # out: two-digit hex value #exit: 0=type found, 1=error, 2=type not found - ptypes="04:TXT 06:BIN B3:S16 E0:SHK F9:P16 FA:INT FC:BAS FF:SYS" - [[ $1 ]] || quit "lookupPdosType:" "no argument supplied ($1)" - [[ ${#1} -eq 3 ]] || return 1 - arg=$(echo -n "$1" | tr [a-z] [A-Z]) - for ptype in $ptypes; do - if [[ ${ptype:3:3} == $arg ]]; then - echo -n "${ptype:0:2}" - return 0 - fi - done - echo "$1" - return 1 + ptypes="04:TXT 06:BIN B3:S16 E0:SHK F9:P16 FA:INT FC:BAS FF:SYS" + [[ $1 ]] || quit "lookupPdosType:" "no argument supplied ($1)" + [[ ${#1} -eq 3 ]] || return 1 + arg=$(echo -n "$1" | tr [a-z] [A-Z]) + for ptype in $ptypes; do + if [[ ${ptype:3:3} == $arg ]]; then + echo -n "${ptype:0:2}" + return 0 + fi + done + echo "$1" + return 1 } verifyTC () { - [[ $1 ]] || return 1 - tcX="$(echo -e -n "$1"X)" - [[ ${#tcX} -eq 5 ]] || return 1 - echo "$tcX" + [[ $1 ]] || return 1 + tcX="$(echo -e -n "$1"X)" + [[ ${#tcX} -eq 5 ]] || return 1 + echo "$tcX" } while [[ $1 && ( "${1:0:1}" == '-' ) ]]; do - if [[ $1 == "-p" ]]; then - [[ $p ]] && exit_usage - shift - p="$1" - shift - continue - elif [[ $1 == "-a" ]]; then - [[ $a ]] && exit_usage - shift - a="$1" - shift - continue - elif [[ $1 == "-t" ]]; then - [[ $t ]] && exit_usage - shift - t="$1" - shift - continue - elif [[ $1 == "-c" ]]; then - [[ $c ]] && exit_usage - shift - c="$1" - shift - continue - elif [[ $1 == "-q" ]]; then - [[ $q ]] && exit_usage - q=1 - shift - continue - else - exit_usage - break - fi + if [[ $1 == "-p" ]]; then + [[ $p ]] && exit_usage + shift + p="$1" + shift + continue + elif [[ $1 == "-a" ]]; then + [[ $a ]] && exit_usage + shift + a="$1" + shift + continue + elif [[ $1 == "-t" ]]; then + [[ $t ]] && exit_usage + shift + t="$1" + shift + continue + elif [[ $1 == "-c" ]]; then + [[ $c ]] && exit_usage + shift + c="$1" + shift + continue + elif [[ $1 == "-q" ]]; then + [[ $q ]] && exit_usage + q=1 + shift + continue + else + exit_usage + break + fi done if [[ ( ( $p || $a ) && ( $t || $c ) ) || ( -z $1 ) ]]; then - exit_usage + exit_usage fi #filename="$1" @@ -372,119 +372,119 @@ fi for filename in $@; do - [[ ${#@} -gt 1 ]] && linestart="($filename) " + [[ ${#@} -gt 1 ]] && linestart="($filename) " - if [[ ! -f $filename ]]; then - echo "${linestart}Not found." - continue - fi + if [[ ! -f $filename ]]; then + echo "${linestart}Not found." + continue + fi - adname="$(dirname "$filename")/.AppleDouble/$(basename "$filename")" - [[ -f $adname ]] && filename=$adname - ADversion=$(readcharDec "$filename" 5) - if [[ ( ( $ADversion -ne 1 ) && ( $ADversion -ne 2 ) ) \ - || ( "$(readchars "$filename" 1 3)" != "$(echo -e -n "\x05\x16\x07")" ) \ - || ( $(readcharDec "$filename" 0) -ne 0 ) \ - || ( $(readcharDec "$filename" 4) -ne 0 ) \ - || ( $(readcharDec "$filename" 6) -ne 0 ) \ - || ( $(readcharDec "$filename" 7) -ne 0 ) ]]; then - echo "${linestart}Not an AppleDouble file." - continue - fi + adname="$(dirname "$filename")/.AppleDouble/$(basename "$filename")" + [[ -f $adname ]] && filename=$adname + ADversion=$(readcharDec "$filename" 5) + if [[ ( ( $ADversion -ne 1 ) && ( $ADversion -ne 2 ) ) \ + || ( "$(readchars "$filename" 1 3)" != "$(echo -e -n "\x05\x16\x07")" ) \ + || ( $(readcharDec "$filename" 0) -ne 0 ) \ + || ( $(readcharDec "$filename" 4) -ne 0 ) \ + || ( $(readcharDec "$filename" 6) -ne 0 ) \ + || ( $(readcharDec "$filename" 7) -ne 0 ) ]]; then + echo "${linestart}Not an AppleDouble file." + continue + fi - entrycount=`readcharDec "$filename" 25` + entrycount=`readcharDec "$filename" 25` - entry=1 - offset=29 + entry=1 + offset=29 - while [[ $(readcharDec "$filename" $offset) -ne 9 ]]; do - (( entry = entry + 1 )) - if (( entry > entrycount )); then - echo "${linestart}Finder Info entry not found in AppleDouble file." - break - fi - (( offset = (entry * 12 + 29) - 12 )) - done - (( entry > entrycount )) && continue + while [[ $(readcharDec "$filename" $offset) -ne 9 ]]; do + (( entry = entry + 1 )) + if (( entry > entrycount )); then + echo "${linestart}Finder Info entry not found in AppleDouble file." + break + fi + (( offset = (entry * 12 + 29) - 12 )) + done + (( entry > entrycount )) && continue - (( offset = offset + 3 )) - (( tposHi = $(readcharDec "$filename" $offset) * 256 )) - (( offset = offset + 1 )) - (( tpos = $(readcharDec "$filename" $offset) + tposHi )) - (( cpos = tpos + 4 )) - (( ppos = tpos + 1 )) - (( apos = tpos + 2 )) + (( offset = offset + 3 )) + (( tposHi = $(readcharDec "$filename" $offset) * 256 )) + (( offset = offset + 1 )) + (( tpos = $(readcharDec "$filename" $offset) + tposHi )) + (( cpos = tpos + 4 )) + (( ppos = tpos + 1 )) + (( apos = tpos + 2 )) - if [[ $p || $a || $t || $c ]]; then # set - if [[ $p || $a ]]; then - if [[ $p ]]; then - [[ ${#p} -eq 3 ]] && { p=$(lookupPdosType $p) || quit "Invalid ProDOS type name ($p)."; } - isHexByte "$p" || quit "Invalid ProDOS file type ($p)." - writecharHex "$filename" $ppos "$p" - fi - if [[ $a ]]; then - isHexByte "${a:0:2}" && isHexByte "${a:2:2}" || quit "Invalid ProDOS aux type ($a)." - writecharHex "$filename" $apos "${a:0:2}" - (( apos=apos+1 )) - writecharHex "$filename" $apos "${a:2:2}" - fi - writechars "$filename" $tpos "p" - writechars "$filename" $cpos "pdos" - elif [[ $t || $c ]]; then - if [[ $t ]]; then - type=$(verifyTC "$t") || quit "$(echo -n "Invalid Mac file type ($t)."; [[ $t == *x* ]] && echo -n " Try quotes."; echo)" - writechars "$filename" $tpos "${type:0:4}" - fi - if [[ $c ]]; then - creator=$(verifyTC "$c") || quit "$(echo -n "Invalid Mac file creator ($c)."; [[ $c == *x* ]] && echo -n " Try quotes."; echo)" - writechars "$filename" $cpos "${creator:0:4}" - fi - fi - [[ $q ]] || { echo -n "${linestart}File changed: "; "$0" "$filename"; } + if [[ $p || $a || $t || $c ]]; then # set + if [[ $p || $a ]]; then + if [[ $p ]]; then + [[ ${#p} -eq 3 ]] && { p=$(lookupPdosType $p) || quit "Invalid ProDOS type name ($p)."; } + isHexByte "$p" || quit "Invalid ProDOS file type ($p)." + writecharHex "$filename" $ppos "$p" + fi + if [[ $a ]]; then + isHexByte "${a:0:2}" && isHexByte "${a:2:2}" || quit "Invalid ProDOS aux type ($a)." + writecharHex "$filename" $apos "${a:0:2}" + (( apos=apos+1 )) + writecharHex "$filename" $apos "${a:2:2}" + fi + writechars "$filename" $tpos "p" + writechars "$filename" $cpos "pdos" + elif [[ $t || $c ]]; then + if [[ $t ]]; then + type=$(verifyTC "$t") || quit "$(echo -n "Invalid Mac file type ($t)."; [[ $t == *x* ]] && echo -n " Try quotes."; echo)" + writechars "$filename" $tpos "${type:0:4}" + fi + if [[ $c ]]; then + creator=$(verifyTC "$c") || quit "$(echo -n "Invalid Mac file creator ($c)."; [[ $c == *x* ]] && echo -n " Try quotes."; echo)" + writechars "$filename" $cpos "${creator:0:4}" + fi + fi + [[ $q ]] || { echo -n "${linestart}File changed: "; "$0" "$filename"; } - else # show - [[ $q ]] && quit "Can only use -q when changing type." + else # show + [[ $q ]] && quit "Can only use -q when changing type." - type="$(readchars "$filename" $tpos 4)" - creator="$(readchars "$filename" $cpos 4)" + type="$(readchars "$filename" $tpos 4)" + creator="$(readchars "$filename" $cpos 4)" - echo -n "$linestart" + echo -n "$linestart" - if [[ $creator != "pdos" || ( ( $type != "TEXT" ) \ - && ( $type != "PSYS" ) && ( ${type:0:1} != "p" ) ) ]]; then - if [[ $creator || $type ]]; then - echo "Mac file. Type:$type Creator:$creator" - else - echo "This file has no Mac or ProDOS file type information." - fi - continue - fi + if [[ $creator != "pdos" || ( ( $type != "TEXT" ) \ + && ( $type != "PSYS" ) && ( ${type:0:1} != "p" ) ) ]]; then + if [[ $creator || $type ]]; then + echo "Mac file. Type:$type Creator:$creator" + else + echo "This file has no Mac or ProDOS file type information." + fi + continue + fi - if [[ $type == "TEXT" ]]; then - pdosType="\$04 [TXT]" - pdosAuxType='$0000' - elif [[ $type == "PSYS" ]]; then - pdosType="\$FF [SYS]" - pdosAuxType='$0000' - else - (( tpos=tpos+1 )) - pdosType=$(readcharHex "$filename" $tpos) - for ptype in $ptypes; do - if [[ "${ptype:0:2}" == "$pdosType" ]]; then - pdosType="$pdosType [${ptype:3:3}]" - break - fi - done + if [[ $type == "TEXT" ]]; then + pdosType="\$04 [TXT]" + pdosAuxType='$0000' + elif [[ $type == "PSYS" ]]; then + pdosType="\$FF [SYS]" + pdosAuxType='$0000' + else + (( tpos=tpos+1 )) + pdosType=$(readcharHex "$filename" $tpos) + for ptype in $ptypes; do + if [[ "${ptype:0:2}" == "$pdosType" ]]; then + pdosType="$pdosType [${ptype:3:3}]" + break + fi + done - (( tpos=tpos+1 )) - auxTypeHi=$(readcharHex "$filename" $tpos) - (( tpos=tpos+1 )) - auxTypeLo=$(readcharHex "$filename" $tpos) - pdosAuxType=$auxTypeHi$auxTypeLo - fi + (( tpos=tpos+1 )) + auxTypeHi=$(readcharHex "$filename" $tpos) + (( tpos=tpos+1 )) + auxTypeLo=$(readcharHex "$filename" $tpos) + pdosAuxType=$auxTypeHi$auxTypeLo + fi - echo "ProDOS file. Type:\$$pdosType AuxType:\$$pdosAuxType" - fi + echo "ProDOS file. Type:\$$pdosType AuxType:\$$pdosAuxType" + fi done diff --git a/scripts/tools/cppo.txt b/scripts/tools/cppo.txt index 07e83fd..9becc6c 100755 --- a/scripts/tools/cppo.txt +++ b/scripts/tools/cppo.txt @@ -1,5 +1,5 @@ #!/usr/bin/env python -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=python: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=python: """cppo: Copy/catalog files from a ProDOS/DOS 3.3/ShrinkIt image/archive. @@ -47,7 +47,7 @@ import tempfile b'ERROR: cppo requires Python 2.6 or later, including 3.x.' class Globals(object): - pass + pass g = Globals() @@ -87,36 +87,36 @@ g.D33 = 0 # (DOS 3.3 image source, selected automatically) # functions def pdosDateToUnixDate(arg1): - # input: ProDOS date/time bit sequence string in format: - # "yyyyyyymmmmddddd000hhhhh00mmmmmm" (ustr) - # output: seconds since Unix epoch (1-Jan-1970), - # or current date/time if no ProDOS date - year = (binToDec(slyce(arg1,0,7)) + 1900) - if (year < 1940): year += 100 - month = binToDec(slyce(arg1,7,4)) - day = binToDec(slyce(arg1,11,5)) - hour = binToDec(slyce(arg1,19,5)) - minute = binToDec(slyce(arg1,26,6)) - # print(year, month, day, hour, minute) - td = (datetime.datetime(year, month, day, hour, minute) - - datetime.datetime(1970,1,1)) - unixDate_naive = (td.days*24*60*60 + td.seconds) - td2 = (datetime.datetime.fromtimestamp(unixDate_naive) - - datetime.datetime.utcfromtimestamp(unixDate_naive)) - utcoffset = (td2.days*24*60*60 + td2.seconds) - # print(unixDate_naive - utcoffset) - return (unixDate_naive - utcoffset) # local time zone with DST + # input: ProDOS date/time bit sequence string in format: + # "yyyyyyymmmmddddd000hhhhh00mmmmmm" (ustr) + # output: seconds since Unix epoch (1-Jan-1970), + # or current date/time if no ProDOS date + year = (binToDec(slyce(arg1,0,7)) + 1900) + if (year < 1940): year += 100 + month = binToDec(slyce(arg1,7,4)) + day = binToDec(slyce(arg1,11,5)) + hour = binToDec(slyce(arg1,19,5)) + minute = binToDec(slyce(arg1,26,6)) + # print(year, month, day, hour, minute) + td = (datetime.datetime(year, month, day, hour, minute) - + datetime.datetime(1970,1,1)) + unixDate_naive = (td.days*24*60*60 + td.seconds) + td2 = (datetime.datetime.fromtimestamp(unixDate_naive) - + datetime.datetime.utcfromtimestamp(unixDate_naive)) + utcoffset = (td2.days*24*60*60 + td2.seconds) + # print(unixDate_naive - utcoffset) + return (unixDate_naive - utcoffset) # local time zone with DST def unixDateToADDate(arg1): - # input: seconds since Unix epoch (1-Jan-1970 00:00:00 GMT) - # output: seconds since Netatalk epoch (1-Jan-2000 00:00:00 GMT), - # in hex-ustr (big endian) - adDate = (arg1 - 946684800) - if (adDate < 0 ): - adDate += 4294967296 # to get negative hex number - adDateHex = to_hex(adDate).zfill(8).upper() - # print(arg1, adDate, adDateHex) - return adDateHex + # input: seconds since Unix epoch (1-Jan-1970 00:00:00 GMT) + # output: seconds since Netatalk epoch (1-Jan-2000 00:00:00 GMT), + # in hex-ustr (big endian) + adDate = (arg1 - 946684800) + if (adDate < 0 ): + adDate += 4294967296 # to get negative hex number + adDateHex = to_hex(adDate).zfill(8).upper() + # print(arg1, adDate, adDateHex) + return adDateHex # cppo support functions: # arg1: directory block or [T,S] containing file entry, or shk file dir path @@ -124,640 +124,640 @@ def unixDateToADDate(arg1): # returns byte position in disk image file def getStartPos(arg1, arg2): - if g.D33: - return (ts(arg1) + (35 * (arg2 % 7)) + 11) - else: # ProDOS - return ( (arg1 * 512) + - (39 * ((arg2 + (arg2 > 11)) % 13)) + - (4 if (arg2 > 11) else 43) ) + if g.D33: + return (ts(arg1) + (35 * (arg2 % 7)) + 11) + else: # ProDOS + return ( (arg1 * 512) + + (39 * ((arg2 + (arg2 > 11)) % 13)) + + (4 if (arg2 > 11) else 43) ) def getStorageType(arg1, arg2): - start = getStartPos(arg1, arg2) - firstByte = readcharDec(g.imageData, start) - return (int(firstByte != 255)*2 if g.D33 else (firstByte//16)) + start = getStartPos(arg1, arg2) + firstByte = readcharDec(g.imageData, start) + return (int(firstByte != 255)*2 if g.D33 else (firstByte//16)) def getFileName(arg1, arg2): - start = getStartPos(arg1, arg2) - if g.D33: - fileNameLo = bytearray() - fileNameHi = readchars(g.imageData, start+3, 30) - for b in fileNameHi: - fileNameLo += to_bytes(to_dec(b)-128) - fileName = bytes(fileNameLo).rstrip() - else: # ProDOS - firstByte = readcharDec(g.imageData, start) - entryType = (firstByte//16) - nameLength = (firstByte - entryType*16) - fileName = readchars(g.imageData, start+1, nameLength) - caseMask = getCaseMask(arg1, arg2) - if (not g.UC and caseMask != None): - for i in range(0, len(fileName)): - if (caseMask[i] == "1"): - fileName = (fileName[:i] + - fileName[i:i+1].lower() + - fileName[i+1:]) - return fileName + start = getStartPos(arg1, arg2) + if g.D33: + fileNameLo = bytearray() + fileNameHi = readchars(g.imageData, start+3, 30) + for b in fileNameHi: + fileNameLo += to_bytes(to_dec(b)-128) + fileName = bytes(fileNameLo).rstrip() + else: # ProDOS + firstByte = readcharDec(g.imageData, start) + entryType = (firstByte//16) + nameLength = (firstByte - entryType*16) + fileName = readchars(g.imageData, start+1, nameLength) + caseMask = getCaseMask(arg1, arg2) + if (not g.UC and caseMask != None): + for i in range(0, len(fileName)): + if (caseMask[i] == "1"): + fileName = (fileName[:i] + + fileName[i:i+1].lower() + + fileName[i+1:]) + return fileName def getCaseMask(arg1, arg2): - start = getStartPos(arg1, arg2) - caseMaskDec = (readcharDec(g.imageData, start+28) + - readcharDec(g.imageData, start+29)*256) - if (caseMaskDec < 32768): - return None - else: - return to_bin(caseMaskDec - 32768).zfill(15) + start = getStartPos(arg1, arg2) + caseMaskDec = (readcharDec(g.imageData, start+28) + + readcharDec(g.imageData, start+29)*256) + if (caseMaskDec < 32768): + return None + else: + return to_bin(caseMaskDec - 32768).zfill(15) def getFileType(arg1, arg2): - if g.SHK: - return arg2.split('#')[1][0:2] - start = getStartPos(arg1, arg2) - if g.D33: - d33fileType = readcharDec(g.imageData, start+2) - if ((d33fileType & 127) == 4): return '06' # BIN - elif ((d33fileType & 127) == 1): return 'FA' # INT - elif ((d33fileType & 127) == 2): return 'FC' # BAS - else: return '04' # TXT or other - else: # ProDOS - return readcharHex(g.imageData, start+16) + if g.SHK: + return arg2.split('#')[1][0:2] + start = getStartPos(arg1, arg2) + if g.D33: + d33fileType = readcharDec(g.imageData, start+2) + if ((d33fileType & 127) == 4): return '06' # BIN + elif ((d33fileType & 127) == 1): return 'FA' # INT + elif ((d33fileType & 127) == 2): return 'FC' # BAS + else: return '04' # TXT or other + else: # ProDOS + return readcharHex(g.imageData, start+16) def getAuxType(arg1, arg2): - if g.SHK: - return arg2.split('#')[1][2:6] - start = getStartPos(arg1, arg2) - if g.D33: - fileType = getFileType(arg1, arg2) - if (fileType == '06'): # BIN (B) - # file address is in first two bytes of file data - fileTSlist = [readcharDec(g.imageData, start+0), - readcharDec(g.imageData, start+1)] - fileStart = [readcharDec(g.imageData, ts(fileTSlist)+12), - readcharDec(g.imageData, ts(fileTSlist)+13)] - return (readcharHex(g.imageData, ts(fileStart)+1) + - readcharHex(g.imageData, ts(fileStart)+0)) - elif (fileType == 'FC'): # BAS (A) - return '0801' - elif (fileType == 'FA'): # INT (I) - return '9600' - else: # TXT (T) or other - return '0000' - else: # ProDOS - return (readcharHex(g.imageData, start+32) + - readcharHex(g.imageData, start+31)) + if g.SHK: + return arg2.split('#')[1][2:6] + start = getStartPos(arg1, arg2) + if g.D33: + fileType = getFileType(arg1, arg2) + if (fileType == '06'): # BIN (B) + # file address is in first two bytes of file data + fileTSlist = [readcharDec(g.imageData, start+0), + readcharDec(g.imageData, start+1)] + fileStart = [readcharDec(g.imageData, ts(fileTSlist)+12), + readcharDec(g.imageData, ts(fileTSlist)+13)] + return (readcharHex(g.imageData, ts(fileStart)+1) + + readcharHex(g.imageData, ts(fileStart)+0)) + elif (fileType == 'FC'): # BAS (A) + return '0801' + elif (fileType == 'FA'): # INT (I) + return '9600' + else: # TXT (T) or other + return '0000' + else: # ProDOS + return (readcharHex(g.imageData, start+32) + + readcharHex(g.imageData, start+31)) def getKeyPointer(arg1, arg2): - start = getStartPos(arg1, arg2) - if g.D33: - return [readcharDec(g.imageData, start+0), - readcharDec(g.imageData, start+1)] - else: # ProDOS - return (readcharDec(g.imageData, start+17) + - readcharDec(g.imageData, start+18)*256) + start = getStartPos(arg1, arg2) + if g.D33: + return [readcharDec(g.imageData, start+0), + readcharDec(g.imageData, start+1)] + else: # ProDOS + return (readcharDec(g.imageData, start+17) + + readcharDec(g.imageData, start+18)*256) def getFileLength(arg1, arg2): - start = getStartPos(arg1, arg2) - if g.D33: - fileType = getFileType(arg1, arg2) - fileTSlist = [readcharDec(g.imageData, start+0), - readcharDec(g.imageData, start+1)] - fileStart = [readcharDec(g.imageData, ts(fileTSlist)+12), - readcharDec(g.imageData, ts(fileTSlist)+13)] - if (fileType == '06'): # BIN (B) - # file length is in second two bytes of file data - return ((readcharDec(g.imageData, ts(fileStart)+2) + - readcharDec(g.imageData, ts(fileStart)+3)*256) + 4) - elif (fileType == 'FC' or fileType == 'FA'): # BAS (A) or INT (I) - # file length is in first two bytes of file data - return ((readcharDec(g.imageData, ts(fileStart)+0) + - readcharDec(g.imageData, ts(fileStart)+1)*256) + 2) - else: # TXT (T) or other - # sadly, we have to walk the whole file - # length is determined by sectors in TSlist, minus wherever - # anything after the first zero in the last sector - fileSize = 0 - lastTSpair = None - nextTSlistSector = fileTSlist - endFound = False - while not endFound: - pos = ts(nextTSlistSector) - for tsPos in range(12, 256, 2): - if ts(readcharDec(g.imageData, pos+tsPos+0), - readcharDec(g.imageData, pos+tsPos+1)) != 0: - fileSize += 256 - prevTSpair = [readcharDec(g.imageData, (pos+tsPos)+0), - readcharDec(g.imageData, (pos+tsPos)+1)] - else: - lastTSpair = prevTSpair - endFound = True - break - if not lastTSpair: - nextTSlistSector = [readcharDec(g.imageData, pos+1), - readcharDec(g.imageData, pos+2)] - if (nextTSlistSector[0]+nextTSlistSector[1] == 0): - lastTSpair = prevTSpair - endFound = True - break - fileSize -= 256 - pos = ts(prevTSpair) - # now find out where the file really ends by finding the last 00 - for offset in range(255, -1, -1): - #print("pos: " + to_hex(pos)) - if (readcharDec(g.imageData, pos+offset) != 0): - fileSize += (offset + 1) - break - return fileSize - else: # ProDOS - return (readcharDec(g.imageData, start+21) + - readcharDec(g.imageData, start+22)*256 + - readcharDec(g.imageData, start+23)*65536) + start = getStartPos(arg1, arg2) + if g.D33: + fileType = getFileType(arg1, arg2) + fileTSlist = [readcharDec(g.imageData, start+0), + readcharDec(g.imageData, start+1)] + fileStart = [readcharDec(g.imageData, ts(fileTSlist)+12), + readcharDec(g.imageData, ts(fileTSlist)+13)] + if (fileType == '06'): # BIN (B) + # file length is in second two bytes of file data + return ((readcharDec(g.imageData, ts(fileStart)+2) + + readcharDec(g.imageData, ts(fileStart)+3)*256) + 4) + elif (fileType == 'FC' or fileType == 'FA'): # BAS (A) or INT (I) + # file length is in first two bytes of file data + return ((readcharDec(g.imageData, ts(fileStart)+0) + + readcharDec(g.imageData, ts(fileStart)+1)*256) + 2) + else: # TXT (T) or other + # sadly, we have to walk the whole file + # length is determined by sectors in TSlist, minus wherever + # anything after the first zero in the last sector + fileSize = 0 + lastTSpair = None + nextTSlistSector = fileTSlist + endFound = False + while not endFound: + pos = ts(nextTSlistSector) + for tsPos in range(12, 256, 2): + if ts(readcharDec(g.imageData, pos+tsPos+0), + readcharDec(g.imageData, pos+tsPos+1)) != 0: + fileSize += 256 + prevTSpair = [readcharDec(g.imageData, (pos+tsPos)+0), + readcharDec(g.imageData, (pos+tsPos)+1)] + else: + lastTSpair = prevTSpair + endFound = True + break + if not lastTSpair: + nextTSlistSector = [readcharDec(g.imageData, pos+1), + readcharDec(g.imageData, pos+2)] + if (nextTSlistSector[0]+nextTSlistSector[1] == 0): + lastTSpair = prevTSpair + endFound = True + break + fileSize -= 256 + pos = ts(prevTSpair) + # now find out where the file really ends by finding the last 00 + for offset in range(255, -1, -1): + #print("pos: " + to_hex(pos)) + if (readcharDec(g.imageData, pos+offset) != 0): + fileSize += (offset + 1) + break + return fileSize + else: # ProDOS + return (readcharDec(g.imageData, start+21) + + readcharDec(g.imageData, start+22)*256 + + readcharDec(g.imageData, start+23)*65536) def getCreationDate(arg1, arg2): - #outputs prodos creation date/time as Unix time - # (seconds since Jan 1 1970 GMT) - #or None if there is none - if g.SHK: - return None - elif g.D33: - return None - else: # ProDOS - start = getStartPos(arg1, arg2) - pdosDate = (hexToBin(readcharHex(g.imageData, start+25)) + - hexToBin(readcharHex(g.imageData, start+24)) + - hexToBin(readcharHex(g.imageData, start+27)) + - hexToBin(readcharHex(g.imageData, start+26))) - try: - rVal = pdosDateToUnixDate(pdosDate) - except Exception: - rVal = None - return rVal + #outputs prodos creation date/time as Unix time + # (seconds since Jan 1 1970 GMT) + #or None if there is none + if g.SHK: + return None + elif g.D33: + return None + else: # ProDOS + start = getStartPos(arg1, arg2) + pdosDate = (hexToBin(readcharHex(g.imageData, start+25)) + + hexToBin(readcharHex(g.imageData, start+24)) + + hexToBin(readcharHex(g.imageData, start+27)) + + hexToBin(readcharHex(g.imageData, start+26))) + try: + rVal = pdosDateToUnixDate(pdosDate) + except Exception: + rVal = None + return rVal def getModifiedDate(arg1, arg2): - #outputs prodos modified date/time as Unix time - # (seconds since Jan 1 1970 GMT) - #or None if there is none + #outputs prodos modified date/time as Unix time + # (seconds since Jan 1 1970 GMT) + #or None if there is none - if g.SHK: - modifiedDate = int(time.mktime( - time.strptime( - time.ctime( - os.path.getmtime(os.path.join(arg1, arg2)))))) - rVal = modifiedDate - elif g.D33: - rVal = None - else: # ProDOS - start = getStartPos(arg1, arg2) - pdosDate = (hexToBin(readcharHex(g.imageData, start+34)) + - hexToBin(readcharHex(g.imageData, start+33)) + - hexToBin(readcharHex(g.imageData, start+36)) + - hexToBin(readcharHex(g.imageData, start+35))) - try: - rVal = pdosDateToUnixDate(pdosDate) - except Exception: - rVal = None - return rVal + if g.SHK: + modifiedDate = int(time.mktime( + time.strptime( + time.ctime( + os.path.getmtime(os.path.join(arg1, arg2)))))) + rVal = modifiedDate + elif g.D33: + rVal = None + else: # ProDOS + start = getStartPos(arg1, arg2) + pdosDate = (hexToBin(readcharHex(g.imageData, start+34)) + + hexToBin(readcharHex(g.imageData, start+33)) + + hexToBin(readcharHex(g.imageData, start+36)) + + hexToBin(readcharHex(g.imageData, start+35))) + try: + rVal = pdosDateToUnixDate(pdosDate) + except Exception: + rVal = None + return rVal def getVolumeName(): - return getWorkingDirName(2) + return getWorkingDirName(2) def getWorkingDirName(arg1, arg2=None): - # arg1:block, arg2:casemask (optional) - start = ( arg1 * 512 ) - firstByte = readcharDec(g.imageData, start+4) - entryType = (firstByte//16) - nameLength = (firstByte - entryType*16) - workingDirName = readchars(g.imageData, start+5, nameLength) - if (entryType == 15): # volume directory, get casemask from header - caseMaskDec = (readcharDec(g.imageData, start+26) + - readcharDec(g.imageData, start+27)*256) - if (caseMaskDec < 32768): - caseMask = None - else: - caseMask = to_bin(caseMaskDec - 32768).zfill(15) - else: # subdirectory, get casemask from arg2 (not available in header) - caseMask = arg2 - if (not g.UC and caseMask != None): - for i in range(0, len(workingDirName)): - if (caseMask[i] == "1"): - workingDirName = (workingDirName[:i] + - workingDirName[i:i+1].lower() + - workingDirName[i+1:]) - return workingDirName + # arg1:block, arg2:casemask (optional) + start = ( arg1 * 512 ) + firstByte = readcharDec(g.imageData, start+4) + entryType = (firstByte//16) + nameLength = (firstByte - entryType*16) + workingDirName = readchars(g.imageData, start+5, nameLength) + if (entryType == 15): # volume directory, get casemask from header + caseMaskDec = (readcharDec(g.imageData, start+26) + + readcharDec(g.imageData, start+27)*256) + if (caseMaskDec < 32768): + caseMask = None + else: + caseMask = to_bin(caseMaskDec - 32768).zfill(15) + else: # subdirectory, get casemask from arg2 (not available in header) + caseMask = arg2 + if (not g.UC and caseMask != None): + for i in range(0, len(workingDirName)): + if (caseMask[i] == "1"): + workingDirName = (workingDirName[:i] + + workingDirName[i:i+1].lower() + + workingDirName[i+1:]) + return workingDirName def getDirEntryCount(arg1): - if g.D33: - entryCount = 0 - #nextSector = [readcharDec(g.imageData, ts(arg1)+1), - # readcharDec(g.imageData, ts(arg1)+2)] - nextSector = arg1 - while True: - top = ts(nextSector) - pos = top+11 - for e in range(0, 7): - if (readcharDec(g.imageData, pos+0) == 0): - return entryCount # no more file entries - else: - if (readcharDec(g.imageData, pos+0) != 255): - entryCount += 1 # increment if not deleted file - pos += 35 - nextSector = [readcharDec(g.imageData, top+1), - readcharDec(g.imageData, top+2)] - if (nextSector[0]+nextSector[1] == 0): # no more catalog sectors - return entryCount - else: # ProDOS - start = ( arg1 * 512 ) - return (readcharDec(g.imageData, start+37) + - readcharDec(g.imageData, start+38)*256) + if g.D33: + entryCount = 0 + #nextSector = [readcharDec(g.imageData, ts(arg1)+1), + # readcharDec(g.imageData, ts(arg1)+2)] + nextSector = arg1 + while True: + top = ts(nextSector) + pos = top+11 + for e in range(0, 7): + if (readcharDec(g.imageData, pos+0) == 0): + return entryCount # no more file entries + else: + if (readcharDec(g.imageData, pos+0) != 255): + entryCount += 1 # increment if not deleted file + pos += 35 + nextSector = [readcharDec(g.imageData, top+1), + readcharDec(g.imageData, top+2)] + if (nextSector[0]+nextSector[1] == 0): # no more catalog sectors + return entryCount + else: # ProDOS + start = ( arg1 * 512 ) + return (readcharDec(g.imageData, start+37) + + readcharDec(g.imageData, start+38)*256) def getDirNextChunkPointer(arg1): - if g.D33: - start = ts(arg1) - return [readcharDec(g.imageData, start+1), - readcharDec(g.imageData, start+2)] - else: # ProDOS - start = ( arg1 * 512 ) - return (readcharDec(g.imageData, start+2) + - readcharDec(g.imageData, start+3)*256) + if g.D33: + start = ts(arg1) + return [readcharDec(g.imageData, start+1), + readcharDec(g.imageData, start+2)] + else: # ProDOS + start = ( arg1 * 512 ) + return (readcharDec(g.imageData, start+2) + + readcharDec(g.imageData, start+3)*256) def toProdosName(name): - i=0 - if (name[0:1] == '.'): # eliminate leading period - name = name[1:] - for c in name: - if (c != '.' and not c.isalnum()): - name = name[:i] + '.' + name[i+1:] - i+=1 - name = name[0:15] - return name + i=0 + if (name[0:1] == '.'): # eliminate leading period + name = name[1:] + for c in name: + if (c != '.' and not c.isalnum()): + name = name[:i] + '.' + name[i+1:] + i+=1 + name = name[0:15] + return name def ts(track, sector=None): - # returns offset; track and sector can be dec, or hex-ustr - # can also supply as [t,s] for convenience - if (sector == None): - sector = track[1] - track = track[0] - if isinstance(track, type("".encode("L1").decode("L1"))): # hex-ustr - track = int(track, 16) - if isinstance(sector, type("".encode("L1").decode("L1"))): # hex-ustr - sector = int(sector, 16) - return (track*16*256)+(sector*256) + # returns offset; track and sector can be dec, or hex-ustr + # can also supply as [t,s] for convenience + if (sector == None): + sector = track[1] + track = track[0] + if isinstance(track, type("".encode("L1").decode("L1"))): # hex-ustr + track = int(track, 16) + if isinstance(sector, type("".encode("L1").decode("L1"))): # hex-ustr + sector = int(sector, 16) + return (track*16*256)+(sector*256) # --- main logic functions def copyFile(arg1, arg2): - #arg1/arg2: - # ProDOS : directory block / file index in overall directory - # DOS 3.3 : [track, sector] / file index in overall VTOC - # ShrinkIt: directory path / file name - # copies file or dfork to g.outFileData, rfork if any to g.exFileData - g.activeFileBytesCopied = 0 + #arg1/arg2: + # ProDOS : directory block / file index in overall directory + # DOS 3.3 : [track, sector] / file index in overall VTOC + # ShrinkIt: directory path / file name + # copies file or dfork to g.outFileData, rfork if any to g.exFileData + g.activeFileBytesCopied = 0 - if g.SHK: - with open(os.path.join(arg1, arg2), 'rb') as infile: - g.outFileData += infile.read() - if g.shk_hasrf: - print(" [data fork]") - if (g.EX or g.AD): - print(" [resource fork]") - if (g.exFileData == None): - g.exFileData = bytearray(b'') - with open(os.path.join(arg1, (arg2 + "r")), 'rb') as infile: - g.exFileData += infile.read() - else: # ProDOS or DOS 3.3 - storageType = getStorageType(arg1, arg2) - keyPointer = getKeyPointer(arg1, arg2) - fileLen = getFileLength(arg1, arg2) - if (storageType == 1): #seedling - copyBlock(keyPointer, fileLen) - elif (storageType == 2): #sapling - processIndexBlock(keyPointer) - elif (storageType == 3): #tree - processMasterIndexBlock(keyPointer) - elif (storageType == 5): #extended (forked) - processForkedFile(keyPointer) - if g.PNAME: - # remove address/length data from DOS 3.3 file data if ProDOS target - if (getFileType(arg1, arg2) == '06'): - g.outFileData = g.outFileData[4:] - elif ((getFileType(arg1, arg2) == 'FA') or - getFileType(arg1, arg2) == 'FC'): - g.outFileData = g.outFileData[2:] + if g.SHK: + with open(os.path.join(arg1, arg2), 'rb') as infile: + g.outFileData += infile.read() + if g.shk_hasrf: + print(" [data fork]") + if (g.EX or g.AD): + print(" [resource fork]") + if (g.exFileData == None): + g.exFileData = bytearray(b'') + with open(os.path.join(arg1, (arg2 + "r")), 'rb') as infile: + g.exFileData += infile.read() + else: # ProDOS or DOS 3.3 + storageType = getStorageType(arg1, arg2) + keyPointer = getKeyPointer(arg1, arg2) + fileLen = getFileLength(arg1, arg2) + if (storageType == 1): #seedling + copyBlock(keyPointer, fileLen) + elif (storageType == 2): #sapling + processIndexBlock(keyPointer) + elif (storageType == 3): #tree + processMasterIndexBlock(keyPointer) + elif (storageType == 5): #extended (forked) + processForkedFile(keyPointer) + if g.PNAME: + # remove address/length data from DOS 3.3 file data if ProDOS target + if (getFileType(arg1, arg2) == '06'): + g.outFileData = g.outFileData[4:] + elif ((getFileType(arg1, arg2) == 'FA') or + getFileType(arg1, arg2) == 'FC'): + g.outFileData = g.outFileData[2:] def copyBlock(arg1, arg2): - #arg1: block number or [t,s] to copy - #arg2: bytes to write (should be 256 (DOS 3.3) or 512 (ProDOS), - # unless final block with less) - #print(arg1 + " " + arg2 + " " + g.activeFileBytesCopied) - if (arg1 == 0): - outBytes = (b'\x00' * arg2) - else: - outBytes = slyce(g.imageData, (ts(arg1) if g.D33 else arg1*512), arg2) - if (g.resourceFork > 0): - if g.AD or g.EX: - offset = (741 if g.AD else 0) - if (g.exFileData == None): - g.exFileData = bytearray(b'') - g.exFileData[(g.activeFileBytesCopied + offset): - (g.activeFileBytesCopied + offset + arg2)] = outBytes - else: - g.outFileData[g.activeFileBytesCopied: - (g.activeFileBytesCopied + arg2)] = outBytes - g.activeFileBytesCopied += arg2 + #arg1: block number or [t,s] to copy + #arg2: bytes to write (should be 256 (DOS 3.3) or 512 (ProDOS), + # unless final block with less) + #print(arg1 + " " + arg2 + " " + g.activeFileBytesCopied) + if (arg1 == 0): + outBytes = (b'\x00' * arg2) + else: + outBytes = slyce(g.imageData, (ts(arg1) if g.D33 else arg1*512), arg2) + if (g.resourceFork > 0): + if g.AD or g.EX: + offset = (741 if g.AD else 0) + if (g.exFileData == None): + g.exFileData = bytearray(b'') + g.exFileData[(g.activeFileBytesCopied + offset): + (g.activeFileBytesCopied + offset + arg2)] = outBytes + else: + g.outFileData[g.activeFileBytesCopied: + (g.activeFileBytesCopied + arg2)] = outBytes + g.activeFileBytesCopied += arg2 def processDir(arg1, arg2=None, arg3=None, arg4=None, arg5=None): - # arg1: ProDOS directory block, or DOS 3.3 [track,sector] - # for key block (with directory header): - # arg2: casemask (optional), arg3:None, arg4:None, arg5:None - # for secondary directory blocks (non-key block): - # arg2/3/4/5: for non-key chunks: entryCount, entry#, - # workingDirName, processedEntryCount + # arg1: ProDOS directory block, or DOS 3.3 [track,sector] + # for key block (with directory header): + # arg2: casemask (optional), arg3:None, arg4:None, arg5:None + # for secondary directory blocks (non-key block): + # arg2/3/4/5: for non-key chunks: entryCount, entry#, + # workingDirName, processedEntryCount - entryCount = None - e = None - pe = None - workingDirName = None + entryCount = None + e = None + pe = None + workingDirName = None - if arg3: - entryCount = arg2 - e = arg3 - workingDirName = arg4 - pe = arg5 - else: - e = 0 - pe = 0 - entryCount = getDirEntryCount(arg1) - if not g.D33: - workingDirName = getWorkingDirName(arg1, arg2).decode("L1") - g.DIRPATH = (g.DIRPATH + "/" + workingDirName) - if g.PDOSPATH_INDEX: - if (g.PDOSPATH_INDEX == 1): - if (("/" + g.PDOSPATH_SEGMENT.lower()) != - g.DIRPATH.lower()): - print("ProDOS volume name does not match disk image.") - quitNow(2) - else: - g.PDOSPATH_INDEX += 1 - g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] - else: - pass - # print(g.DIRPATH) - while (pe < entryCount): - if (getStorageType(arg1, e) > 0): - #print(pe, e, entryCount) - processEntry(arg1, e) - pe += 1 - e += 1 - if not ((e + (0 if g.D33 else (e>11)) ) % (7 if g.D33 else 13)): - processDir(getDirNextChunkPointer(arg1), - entryCount, - e, - workingDirName, - pe) - break + if arg3: + entryCount = arg2 + e = arg3 + workingDirName = arg4 + pe = arg5 + else: + e = 0 + pe = 0 + entryCount = getDirEntryCount(arg1) + if not g.D33: + workingDirName = getWorkingDirName(arg1, arg2).decode("L1") + g.DIRPATH = (g.DIRPATH + "/" + workingDirName) + if g.PDOSPATH_INDEX: + if (g.PDOSPATH_INDEX == 1): + if (("/" + g.PDOSPATH_SEGMENT.lower()) != + g.DIRPATH.lower()): + print("ProDOS volume name does not match disk image.") + quitNow(2) + else: + g.PDOSPATH_INDEX += 1 + g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] + else: + pass + # print(g.DIRPATH) + while (pe < entryCount): + if (getStorageType(arg1, e) > 0): + #print(pe, e, entryCount) + processEntry(arg1, e) + pe += 1 + e += 1 + if not ((e + (0 if g.D33 else (e>11)) ) % (7 if g.D33 else 13)): + processDir(getDirNextChunkPointer(arg1), + entryCount, + e, + workingDirName, + pe) + break def processEntry(arg1, arg2): - # arg1=block number, [t,s] if g.D33=1, or subdir name if g.SHK=1 - # arg2=index number of entry in directory, or file name if g.SHK=1 + # arg1=block number, [t,s] if g.D33=1, or subdir name if g.SHK=1 + # arg2=index number of entry in directory, or file name if g.SHK=1 - ''' - print(getFileName(arg1, arg2), getStorageType(arg1, arg2), - getFileType(arg1, arg2), getKeyPointer(arg1, arg2), - getFileLength(arg1, arg2), getAuxType(arg1, arg2), - getCreationDate(arg1, arg2), getModifiedDate(arg1, arg2)) - ''' + ''' + print(getFileName(arg1, arg2), getStorageType(arg1, arg2), + getFileType(arg1, arg2), getKeyPointer(arg1, arg2), + getFileLength(arg1, arg2), getAuxType(arg1, arg2), + getCreationDate(arg1, arg2), getModifiedDate(arg1, arg2)) + ''' - eTargetName = None - g.exFileData = None - g.outFileData = bytearray(b'') - if g.SHK: # ShrinkIt archive - g.activeFileName = (arg2 if g.EX else arg2.split('#')[0]) - if g.UC: - g.activeFileName = g.activeFileName.upper() - origFileName = g.activeFileName - else: # ProDOS or DOS 3.3 image - g.activeFileName = getFileName(arg1 ,arg2).decode("L1") - origFileName = g.activeFileName - if g.PNAME: - g.activeFileName = toProdosName(g.activeFileName) - g.activeFileSize = getFileLength(arg1, arg2) + eTargetName = None + g.exFileData = None + g.outFileData = bytearray(b'') + if g.SHK: # ShrinkIt archive + g.activeFileName = (arg2 if g.EX else arg2.split('#')[0]) + if g.UC: + g.activeFileName = g.activeFileName.upper() + origFileName = g.activeFileName + else: # ProDOS or DOS 3.3 image + g.activeFileName = getFileName(arg1 ,arg2).decode("L1") + origFileName = g.activeFileName + if g.PNAME: + g.activeFileName = toProdosName(g.activeFileName) + g.activeFileSize = getFileLength(arg1, arg2) - if (not g.PDOSPATH_INDEX or - g.activeFileName.upper() == g.PDOSPATH_SEGMENT.upper()): + if (not g.PDOSPATH_INDEX or + g.activeFileName.upper() == g.PDOSPATH_SEGMENT.upper()): - # if ProDOS directory, not file - if (not g.SHK and getStorageType(arg1, arg2) == 13): - if not g.PDOSPATH_INDEX: - g.targetDir = (g.targetDir + "/" + g.activeFileName) - g.ADdir = (g.targetDir + "/.AppleDouble") - if not (g.CAT or os.path.isdir(g.targetDir)): - makedirs(g.targetDir) - if not (g.CAT or (not g.AD) or os.path.isdir(g.ADdir)): - makedirs(g.ADdir) - if g.PDOSPATH_SEGMENT: - g.PDOSPATH_INDEX += 1 - g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] - processDir(getKeyPointer(arg1, arg2), getCaseMask(arg1, arg2)) - g.DIRPATH = g.DIRPATH.rsplit("/", 1)[0] - if not g.PDOSPATH_INDEX: - g.targetDir = g.targetDir.rsplit("/", 1)[0] - g.ADdir = (g.targetDir + "/.AppleDouble") - else: # ProDOS or DOS 3.3 file either from image or ShrinkIt archive - dirPrint = "" - if g.DIRPATH: - dirPrint = g.DIRPATH + "/" - else: - if g.SHK: - if ("/".join(dirName.split('/')[3:])): - dirPrint = ("/".join(dirName.split('/')[3:]) + "/") - if (not g.extractFile or - (os.path.basename(g.extractFile.lower()) == - origFileName.split('#')[0].lower())): - filePrint = g.activeFileName.split("#")[0] - print(dirPrint + filePrint + - ("+" if (g.shk_hasrf or - (not g.SHK and getStorageType(arg1, arg2) == 5)) - else "") + - ((" [" + origFileName + "] ") - if (g.PNAME and (origFileName != g.activeFileName)) - else "")) - if g.CAT: - return - if not g.targetName: - g.targetName = g.activeFileName - if g.EX: - if g.SHK: - eTargetName = arg2 - else: # ProDOS image - eTargetName = (g.targetName + "#" + - getFileType(arg1, arg2).lower() + - getAuxType(arg1, arg2).lower()) - # touch(g.targetDir + "/" + g.targetName) - if g.AD: - makeADfile() - copyFile(arg1, arg2) - saveName = (g.targetDir + "/" + - (eTargetName if eTargetName else g.targetName)) - saveFile(saveName, g.outFileData) - creationDate = getCreationDate(arg1, arg2) - modifiedDate = getModifiedDate(arg1, arg2) - if (creationDate is None and modifiedDate is not None): - creationDate = modifiedDate - elif (creationDate is not None and modifiedDate is None): - modifiedDate = creationDate - elif (creationDate is None and modifiedDate is None): - creationDate = (datetime.datetime.today() - - datetime.datetime(1970,1,1)).days*24*60*60 - modifiedDate = creationDate - if g.AD: # AppleDouble - # set dates - ADfilePath = (g.ADdir + "/" + g.targetName) - writecharsHex(g.exFileData, - 637, - (unixDateToADDate(creationDate) + - unixDateToADDate(modifiedDate))) - writecharHex(g.exFileData, 645, "80") - writecharHex(g.exFileData, 649, "80") - #set type/creator - writechars(g.exFileData, 653, b'p') - writecharsHex(g.exFileData, - 654, - getFileType(arg1, arg2) + - getAuxType(arg1, arg2)) - writechars(g.exFileData, 657, b'pdos') - saveFile(ADfilePath, g.exFileData) - touch(saveName, modifiedDate) - if g.EX: # extended name from ProDOS image - if (g.exFileData != None): - saveFile((saveName + "r"), g.exFileData) - touch((saveName + "r"), modifiedDate) - if (g.PDOSPATH_SEGMENT or - (g.extractFile and - (g.extractFile.lower() == origFileName.lower()))): - quitNow(0) - g.targetName = None - #else: - #print(g.activeFileName + " doesn't match " + g.PDOSPATH_SEGMENT) + # if ProDOS directory, not file + if (not g.SHK and getStorageType(arg1, arg2) == 13): + if not g.PDOSPATH_INDEX: + g.targetDir = (g.targetDir + "/" + g.activeFileName) + g.ADdir = (g.targetDir + "/.AppleDouble") + if not (g.CAT or os.path.isdir(g.targetDir)): + makedirs(g.targetDir) + if not (g.CAT or (not g.AD) or os.path.isdir(g.ADdir)): + makedirs(g.ADdir) + if g.PDOSPATH_SEGMENT: + g.PDOSPATH_INDEX += 1 + g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] + processDir(getKeyPointer(arg1, arg2), getCaseMask(arg1, arg2)) + g.DIRPATH = g.DIRPATH.rsplit("/", 1)[0] + if not g.PDOSPATH_INDEX: + g.targetDir = g.targetDir.rsplit("/", 1)[0] + g.ADdir = (g.targetDir + "/.AppleDouble") + else: # ProDOS or DOS 3.3 file either from image or ShrinkIt archive + dirPrint = "" + if g.DIRPATH: + dirPrint = g.DIRPATH + "/" + else: + if g.SHK: + if ("/".join(dirName.split('/')[3:])): + dirPrint = ("/".join(dirName.split('/')[3:]) + "/") + if (not g.extractFile or + (os.path.basename(g.extractFile.lower()) == + origFileName.split('#')[0].lower())): + filePrint = g.activeFileName.split("#")[0] + print(dirPrint + filePrint + + ("+" if (g.shk_hasrf or + (not g.SHK and getStorageType(arg1, arg2) == 5)) + else "") + + ((" [" + origFileName + "] ") + if (g.PNAME and (origFileName != g.activeFileName)) + else "")) + if g.CAT: + return + if not g.targetName: + g.targetName = g.activeFileName + if g.EX: + if g.SHK: + eTargetName = arg2 + else: # ProDOS image + eTargetName = (g.targetName + "#" + + getFileType(arg1, arg2).lower() + + getAuxType(arg1, arg2).lower()) + # touch(g.targetDir + "/" + g.targetName) + if g.AD: + makeADfile() + copyFile(arg1, arg2) + saveName = (g.targetDir + "/" + + (eTargetName if eTargetName else g.targetName)) + saveFile(saveName, g.outFileData) + creationDate = getCreationDate(arg1, arg2) + modifiedDate = getModifiedDate(arg1, arg2) + if (creationDate is None and modifiedDate is not None): + creationDate = modifiedDate + elif (creationDate is not None and modifiedDate is None): + modifiedDate = creationDate + elif (creationDate is None and modifiedDate is None): + creationDate = (datetime.datetime.today() - + datetime.datetime(1970,1,1)).days*24*60*60 + modifiedDate = creationDate + if g.AD: # AppleDouble + # set dates + ADfilePath = (g.ADdir + "/" + g.targetName) + writecharsHex(g.exFileData, + 637, + (unixDateToADDate(creationDate) + + unixDateToADDate(modifiedDate))) + writecharHex(g.exFileData, 645, "80") + writecharHex(g.exFileData, 649, "80") + #set type/creator + writechars(g.exFileData, 653, b'p') + writecharsHex(g.exFileData, + 654, + getFileType(arg1, arg2) + + getAuxType(arg1, arg2)) + writechars(g.exFileData, 657, b'pdos') + saveFile(ADfilePath, g.exFileData) + touch(saveName, modifiedDate) + if g.EX: # extended name from ProDOS image + if (g.exFileData != None): + saveFile((saveName + "r"), g.exFileData) + touch((saveName + "r"), modifiedDate) + if (g.PDOSPATH_SEGMENT or + (g.extractFile and + (g.extractFile.lower() == origFileName.lower()))): + quitNow(0) + g.targetName = None + #else: + #print(g.activeFileName + " doesn't match " + g.PDOSPATH_SEGMENT) def processForkedFile(arg1): - # finder info except type/creator - fInfoA_entryType = readcharDec(g.imageData, 9) - fInfoB_entryType = readcharDec(g.imageData, 27) - if (fInfoA_entryType == 1): - writechars(g.imageData, 661, readchars(g.imageData, 18, 8)) - elif (fInfoA_entryType == 2): - writechars(g.imageData, 669, readchars(g.imageData, 10, 16)) - if (fInfoB_entryType == 1): - writechars(g.imageData, 661, readchars(g.imageData, 36, 8)) - elif (fInfoB_entryType == 2): - writechars(g.imageData, 669, readchars(g.imageData, 28, 16)) + # finder info except type/creator + fInfoA_entryType = readcharDec(g.imageData, 9) + fInfoB_entryType = readcharDec(g.imageData, 27) + if (fInfoA_entryType == 1): + writechars(g.imageData, 661, readchars(g.imageData, 18, 8)) + elif (fInfoA_entryType == 2): + writechars(g.imageData, 669, readchars(g.imageData, 10, 16)) + if (fInfoB_entryType == 1): + writechars(g.imageData, 661, readchars(g.imageData, 36, 8)) + elif (fInfoB_entryType == 2): + writechars(g.imageData, 669, readchars(g.imageData, 28, 16)) - for f in [0, 256]: - g.resourceFork = f - g.activeFileBytesCopied = 0 - forkStart = (arg1 * 512) # start of Forked File key block - # print("--" + forkStart) - forkStorageType = readcharDec(g.imageData, forkStart+f+0) - forkKeyPointer = (readcharDec(g.imageData, forkStart+f+1) + - readcharDec(g.imageData, forkStart+f+2)*256) - forkFileLen = (readcharDec(g.imageData, forkStart+f+5) + - readcharDec(g.imageData, forkStart+f+6)*256 + - readcharDec(g.imageData, forkStart+f+7)*256*256) - g.activeFileSize = forkFileLen - if (g.resourceFork > 0): - rsrcForkLenHex = (readcharHex(g.imageData, forkStart+f+7) + - readcharHex(g.imageData, forkStart+f+6) + - readcharHex(g.imageData, forkStart+f+5)) - # print(">>>" + rsrcForkLenHex) - if (g.AD or g.EX): - print(" [resource fork]") - if g.AD: - writecharsHex(g.exFileData, 35, rsrcForkLenHex) - else: - print(" [data fork]") - if (forkStorageType == 1): #seedling - copyBlock(forkKeyPointer, forkFileLen) - elif (forkStorageType == 2): #sapling - processIndexBlock(forkKeyPointer) - elif (forkStorageType == 3): #tree - processMasterIndexBlock(forkKeyPointer) - # print() - g.resourceFork = 0 + for f in [0, 256]: + g.resourceFork = f + g.activeFileBytesCopied = 0 + forkStart = (arg1 * 512) # start of Forked File key block + # print("--" + forkStart) + forkStorageType = readcharDec(g.imageData, forkStart+f+0) + forkKeyPointer = (readcharDec(g.imageData, forkStart+f+1) + + readcharDec(g.imageData, forkStart+f+2)*256) + forkFileLen = (readcharDec(g.imageData, forkStart+f+5) + + readcharDec(g.imageData, forkStart+f+6)*256 + + readcharDec(g.imageData, forkStart+f+7)*256*256) + g.activeFileSize = forkFileLen + if (g.resourceFork > 0): + rsrcForkLenHex = (readcharHex(g.imageData, forkStart+f+7) + + readcharHex(g.imageData, forkStart+f+6) + + readcharHex(g.imageData, forkStart+f+5)) + # print(">>>" + rsrcForkLenHex) + if (g.AD or g.EX): + print(" [resource fork]") + if g.AD: + writecharsHex(g.exFileData, 35, rsrcForkLenHex) + else: + print(" [data fork]") + if (forkStorageType == 1): #seedling + copyBlock(forkKeyPointer, forkFileLen) + elif (forkStorageType == 2): #sapling + processIndexBlock(forkKeyPointer) + elif (forkStorageType == 3): #tree + processMasterIndexBlock(forkKeyPointer) + # print() + g.resourceFork = 0 def processMasterIndexBlock(arg1): - processIndexBlock(arg1, True) + processIndexBlock(arg1, True) def processIndexBlock(arg1, arg2=False): - #arg1: indexBlock, or [t,s] of track/sector list - #arg2: if True, it's a Master Index Block - pos = 12 if g.D33 else 0 - bytesRemaining = g.activeFileSize - while (g.activeFileBytesCopied < g.activeFileSize): - if g.D33: - targetTS = [readcharDec(g.imageData, ts(arg1)+pos+0), - readcharDec(g.imageData, ts(arg1)+pos+1)] - #print(to_hex(targetTS[0]),to_hex(targetTS[1])) - bytesRemaining = (g.activeFileSize - g.activeFileBytesCopied) - bs = (bytesRemaining if (bytesRemaining < 256) else 256) - copyBlock(targetTS, bs) - pos += 2 - if (pos > 255): - # continue with next T/S list sector - processIndexBlock([readcharDec(g.imageData, ts(arg1)+1), - readcharDec(g.imageData, ts(arg1)+2)]) - else: # ProDOS - targetBlock = (readcharDec(g.imageData, arg1*512+pos) + - readcharDec(g.imageData, arg1*512+(pos+256))*256) - if arg2: - processIndexBlock(targetBlock) - else: - bytesRemaining = (g.activeFileSize - g.activeFileBytesCopied) - bs = (bytesRemaining if (bytesRemaining < 512) else 512) - copyBlock(targetBlock, bs) - pos += 1 - if (pos > 255): - break # go to next entry in Master Index Block (tree) + #arg1: indexBlock, or [t,s] of track/sector list + #arg2: if True, it's a Master Index Block + pos = 12 if g.D33 else 0 + bytesRemaining = g.activeFileSize + while (g.activeFileBytesCopied < g.activeFileSize): + if g.D33: + targetTS = [readcharDec(g.imageData, ts(arg1)+pos+0), + readcharDec(g.imageData, ts(arg1)+pos+1)] + #print(to_hex(targetTS[0]),to_hex(targetTS[1])) + bytesRemaining = (g.activeFileSize - g.activeFileBytesCopied) + bs = (bytesRemaining if (bytesRemaining < 256) else 256) + copyBlock(targetTS, bs) + pos += 2 + if (pos > 255): + # continue with next T/S list sector + processIndexBlock([readcharDec(g.imageData, ts(arg1)+1), + readcharDec(g.imageData, ts(arg1)+2)]) + else: # ProDOS + targetBlock = (readcharDec(g.imageData, arg1*512+pos) + + readcharDec(g.imageData, arg1*512+(pos+256))*256) + if arg2: + processIndexBlock(targetBlock) + else: + bytesRemaining = (g.activeFileSize - g.activeFileBytesCopied) + bs = (bytesRemaining if (bytesRemaining < 512) else 512) + copyBlock(targetBlock, bs) + pos += 1 + if (pos > 255): + break # go to next entry in Master Index Block (tree) def makeADfile(): - if not g.AD: return - touch(g.ADdir + "/" + g.targetName) - g.exFileData = bytearray(b'\x00' * 741) - # ADv2 header - writecharsHex(g.exFileData, hexToDec("00"), "0005160700020000") - # number of entries - writecharsHex(g.exFileData, hexToDec("18"), "000D") - # Resource Fork - writecharsHex(g.exFileData, hexToDec("1A"), "00000002000002E500000000") - # Real Name - writecharsHex(g.exFileData, hexToDec("26"), "00000003000000B600000000") - # Comment - writecharsHex(g.exFileData, hexToDec("32"), "00000004000001B500000000") - # Dates Info - writecharsHex(g.exFileData, hexToDec("3E"), "000000080000027D00000010") - # Finder Info - writecharsHex(g.exFileData, hexToDec("4A"), "000000090000028D00000020") - # ProDOS file info - writecharsHex(g.exFileData, hexToDec("56"), "0000000B000002C100000008") - # AFP short name - writecharsHex(g.exFileData, hexToDec("62"), "0000000D000002B500000000") - # AFP File Info - writecharsHex(g.exFileData, hexToDec("6E"), "0000000E000002B100000004") - # AFP Directory ID - writecharsHex(g.exFileData, hexToDec("7A"), "0000000F000002AD00000004") - # dbd (second time) will create DEV, INO, SYN, SV~ + if not g.AD: return + touch(g.ADdir + "/" + g.targetName) + g.exFileData = bytearray(b'\x00' * 741) + # ADv2 header + writecharsHex(g.exFileData, hexToDec("00"), "0005160700020000") + # number of entries + writecharsHex(g.exFileData, hexToDec("18"), "000D") + # Resource Fork + writecharsHex(g.exFileData, hexToDec("1A"), "00000002000002E500000000") + # Real Name + writecharsHex(g.exFileData, hexToDec("26"), "00000003000000B600000000") + # Comment + writecharsHex(g.exFileData, hexToDec("32"), "00000004000001B500000000") + # Dates Info + writecharsHex(g.exFileData, hexToDec("3E"), "000000080000027D00000010") + # Finder Info + writecharsHex(g.exFileData, hexToDec("4A"), "000000090000028D00000020") + # ProDOS file info + writecharsHex(g.exFileData, hexToDec("56"), "0000000B000002C100000008") + # AFP short name + writecharsHex(g.exFileData, hexToDec("62"), "0000000D000002B500000000") + # AFP File Info + writecharsHex(g.exFileData, hexToDec("6E"), "0000000E000002B100000004") + # AFP Directory ID + writecharsHex(g.exFileData, hexToDec("7A"), "0000000F000002AD00000004") + # dbd (second time) will create DEV, INO, SYN, SV~ def quitNow(exitCode=0): - if (exitCode == 0 and not g.nomsg and - g.AD and os.path.isdir("/usr/local/etc/netatalk")): - print("File(s) have been copied to the target directory. " + - "If the directory") - print("is shared by Netatalk, please type 'afpsync' now.") - if g.SHK: # clean up - for file in os.listdir('/tmp'): - if file.startswith("cppo-"): - shutil.rmtree('/tmp' + "/" + file) - sys.exit(exitCode) + if (exitCode == 0 and not g.nomsg and + g.AD and os.path.isdir("/usr/local/etc/netatalk")): + print("File(s) have been copied to the target directory. " + + "If the directory") + print("is shared by Netatalk, please type 'afpsync' now.") + if g.SHK: # clean up + for file in os.listdir('/tmp'): + if file.startswith("cppo-"): + shutil.rmtree('/tmp' + "/" + file) + sys.exit(exitCode) def usage(exitcode=1): - print(sys.modules[__name__].__doc__) - quitNow(exitcode) + print(sys.modules[__name__].__doc__) + quitNow(exitcode) # --- ID bashbyter functions (adapted) @@ -766,70 +766,70 @@ def decToHex(arg1): # arg: decimal value from 0-255 # out: two-digit hex string from 00-FF #exit: 21=invalid arg - if (arg1<0 or arg1>255): sys.exit(21) - return to_hex(arg1).upper() + if (arg1<0 or arg1>255): sys.exit(21) + return to_hex(arg1).upper() def hexToDec(arg1): # converts single-byte hexadecimal value to decimal equivalent # arg: two-digit hex value from 00-FF # out: decimal value #exit: 21=invalid arg - if (len(arg1) != 2): return 21 - return to_dec(arg1) + if (len(arg1) != 2): return 21 + return to_dec(arg1) def hexToBin(arg1): # converts single-byte hexadecimal value to binary string # arg: two-digit hex value from 00-FF # out: binary string value #exit: 21=invalid arg - if (len(arg1) != 2): return 21 - return to_bin(arg1).zfill(8) + if (len(arg1) != 2): return 21 + return to_bin(arg1).zfill(8) def binToDec(arg1): # converts single-byte binary string (8 bits) value to decimal # warning: no error checking # arg: binary string up to 8 bits # out: decimal value - return to_dec([arg1]) + return to_dec([arg1]) def binToHex(arg1): # converts single-byte binary string (8 bits) value to hex # warning: no error checking # arg: binary string up to 8 bits # out: hex value - return to_hex(arg1).upper() + return to_hex(arg1).upper() def charToDec(arg1): # converts single char (of type bytes) to corresponding decimal value # arg: one char (of type bytes) # out: decimal value from 0-255 #exit: 21=invalid arg - if (len(arg1) != 1): return 21 - return to_dec(arg1) + if (len(arg1) != 1): return 21 + return to_dec(arg1) def charToHex(arg1): # converts single char (of type bytes) to corresponding hex value # arg: one char (of type bytes) # out: hexadecimal value from 00-FF #exit: 21=invalid arg - if (len(arg1) != 1): return 21 - return to_hex(arg1).upper() + if (len(arg1) != 1): return 21 + return to_hex(arg1).upper() def decToChar(arg1): # converts single-byte decimal value to equivalent char (of type bytes) # arg: decimal number from 0-255 # out: one character #exit: 21=invalid arg - if (arg1<0 or arg1>255): sys.exit(21) - return to_bytes(arg1) + if (arg1<0 or arg1>255): sys.exit(21) + return to_bytes(arg1) def hexToChar(arg1): # converts single-byte hex value to corresponding char (of type bytes) # arg: two-digit hexadecimal number from 00-FF # out: one character #exit: 21=invalid arg - if (len(arg1) != 2): return 21 - return to_bytes(arg1) + if (len(arg1) != 2): return 21 + return to_bytes(arg1) def readchars(arg1, arg2=0, arg3=0): # read one or more characters from a bytes variable @@ -838,13 +838,13 @@ def readchars(arg1, arg2=0, arg3=0): # arg3: (optional) # of chars to read (default is to end of bytes var) # out: sequence of characters (bytes or bytearray) # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 - if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): - sys.exit(21) - if (arg2<0): sys.exit(22) - if (arg3<0): sys.exit(23) - if (arg3 == 0): - arg3 = len(arg1) - return slyce(arg1, arg2, arg3) + if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): + sys.exit(21) + if (arg2<0): sys.exit(22) + if (arg3<0): sys.exit(23) + if (arg3 == 0): + arg3 = len(arg1) + return slyce(arg1, arg2, arg3) def readcharDec(arg1, arg2=0): # read one character from bytes var & convert to equivalent dec value @@ -852,10 +852,10 @@ def readcharDec(arg1, arg2=0): # arg2: (optional) offset (# of bytes to skip before reading) # out: decimal value from 0-255 # exit: 21=invalid arg1, 22=invalid arg2 - if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): - sys.exit(21) - if (arg2<0): sys.exit(22) - return to_dec(slyce(arg1, arg2, 1)) + if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): + sys.exit(21) + if (arg2<0): sys.exit(22) + return to_dec(slyce(arg1, arg2, 1)) def readcharHex(arg1, arg2=0): # read one character from bytes var & convert to corresponding hex value @@ -863,10 +863,10 @@ def readcharHex(arg1, arg2=0): # arg2: (optional) offset (# of bytes to skip before reading) # out: two-digit hex value from 00-FF # exit: 21=invalid arg1, 22=invalid arg2 - if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): - sys.exit(21) - if (arg2<0): sys.exit(22) - return to_hex(slyce(arg1, arg2, 1)) + if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): + sys.exit(21) + if (arg2<0): sys.exit(22) + return to_hex(slyce(arg1, arg2, 1)) def writechars(arg1, arg2, arg3): # write one or more characters (bytes) to bytearray @@ -875,11 +875,11 @@ def writechars(arg1, arg2, arg3): # arg3: sequence of bytes (or bytearray) # out: nothing # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 - if not isinstance(arg1, bytearray): sys.exit(21) - if (arg2<0): sys.exit(22) - if not (isinstance(arg3, bytes) or isinstance(arg3, bytearray)): - sys.exit(23) - arg1[arg2:arg2+len(arg3)] = arg3 + if not isinstance(arg1, bytearray): sys.exit(21) + if (arg2<0): sys.exit(22) + if not (isinstance(arg3, bytes) or isinstance(arg3, bytearray)): + sys.exit(23) + arg1[arg2:arg2+len(arg3)] = arg3 def writecharDec(arg1, arg2, arg3): # write corresponding char of single-byte decimal value into bytearray @@ -888,10 +888,10 @@ def writecharDec(arg1, arg2, arg3): # arg3: decimal number from 0-255 # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 # out: nothing - if not isinstance(arg1, bytearray): sys.exit(21) - if (arg2<0): sys.exit(22) - if not isnumber(arg3): sys.exit(23) - arg1[arg2:arg2+1] = to_bytes(arg3) + if not isinstance(arg1, bytearray): sys.exit(21) + if (arg2<0): sys.exit(22) + if not isnumber(arg3): sys.exit(23) + arg1[arg2:arg2+1] = to_bytes(arg3) def writecharHex(arg1, arg2, arg3): # write corresponding character of single-byte hex value into bytearray @@ -900,10 +900,10 @@ def writecharHex(arg1, arg2, arg3): # arg3: two-digit hexadecimal number from 00-FF # out: nothing # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 - if not isinstance(arg1, bytearray): sys.exit(21) - if (arg2<0): sys.exit(22) - if not isinstance(arg3, type("".encode("L1").decode("L1"))): sys.exit(23) - arg1[arg2:arg2+1] = to_bytes(arg3) + if not isinstance(arg1, bytearray): sys.exit(21) + if (arg2<0): sys.exit(22) + if not isinstance(arg3, type("".encode("L1").decode("L1"))): sys.exit(23) + arg1[arg2:arg2+1] = to_bytes(arg3) def writecharsHex(arg1, arg2, arg3): # write corresponding characters of hex values into bytearray @@ -912,183 +912,183 @@ def writecharsHex(arg1, arg2, arg3): # arg3: string of two-digit hexadecimal numbers from 00-FF # out: nothing # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 - if not isinstance(arg1, bytearray): sys.exit(21) - if (arg2<0): sys.exit(22) - if not isinstance(arg3, type("".encode("L1").decode("L1"))): sys.exit(23) - arg1[arg2:arg2+len(to_bytes(arg3))] = to_bytes(arg3) + if not isinstance(arg1, bytearray): sys.exit(21) + if (arg2<0): sys.exit(22) + if not isinstance(arg3, type("".encode("L1").decode("L1"))): sys.exit(23) + arg1[arg2:arg2+len(to_bytes(arg3))] = to_bytes(arg3) #---- IvanX general purpose functions ----# def slyce(val, start_pos=0, length=1, reverse=False): - """returns slice of object (but not a slice object) - allows specifying length, and 3.x "bytes" consistency""" - if (start_pos < 0): - the_slyce = val[start_pos:] - else: - the_slyce = val[start_pos:start_pos+length] - return (the_slyce[::-1] if reverse else the_slyce) + """returns slice of object (but not a slice object) + allows specifying length, and 3.x "bytes" consistency""" + if (start_pos < 0): + the_slyce = val[start_pos:] + else: + the_slyce = val[start_pos:start_pos+length] + return (the_slyce[::-1] if reverse else the_slyce) def to_hex(val): - """convert bytes, decimal number, or [bin-ustr] to two-digit hex values - unlike hex(), accepts bytes; has no leading 0x or trailing L""" - from binascii import b2a_hex - if isinstance(val, list): # [bin-ustr] - val = int(val[0], 2) - if isinstance(val, bytes): # bytes - return b2a_hex(val).decode("L1") - elif isnumber(val): - # hex returns str/bytes in P2, but str/unicode in P3, so - # .encode().decode() always returns unicode in either - if (val < 0): print ("val: " + str(val)) - return hex(val)[2:].encode("L1").decode("L1").split("L")[0] - else: - raise Exception("to_hex() requires bytes, int/long, or [bin-ustr]") + """convert bytes, decimal number, or [bin-ustr] to two-digit hex values + unlike hex(), accepts bytes; has no leading 0x or trailing L""" + from binascii import b2a_hex + if isinstance(val, list): # [bin-ustr] + val = int(val[0], 2) + if isinstance(val, bytes): # bytes + return b2a_hex(val).decode("L1") + elif isnumber(val): + # hex returns str/bytes in P2, but str/unicode in P3, so + # .encode().decode() always returns unicode in either + if (val < 0): print ("val: " + str(val)) + return hex(val)[2:].encode("L1").decode("L1").split("L")[0] + else: + raise Exception("to_hex() requires bytes, int/long, or [bin-ustr]") def hex_slyce(val, start_pos=0, length=1, little_endian=False): - """returns bytes slyce as hex-ustr""" - return to_hex(slyce(val, start_pos, length, little_endian)) + """returns bytes slyce as hex-ustr""" + return to_hex(slyce(val, start_pos, length, little_endian)) def dec_slyce(val, start_pos=0, length=1, little_endian=False): - """returns bytes slyce converted to decimal int/long""" - return to_dec(hex_slyce(val, start_pos, length, little_endian)) + """returns bytes slyce converted to decimal int/long""" + return to_dec(hex_slyce(val, start_pos, length, little_endian)) def bin_slyce(val, start_pos=0, length=1, little_endian=False): - """returns bytes slyce converted to bin-ustr""" - return to_bin(hex_slyce(val, start_pos, length, little_endian)) + """returns bytes slyce converted to bin-ustr""" + return to_bin(hex_slyce(val, start_pos, length, little_endian)) def to_dec(val): - """convert bytes, hex-ustr or [bin-ustr] to decimal int/long""" - if isinstance(val, list): # [bin-ustr] - return int(val[0], 2) - elif isinstance(val, bytes): # bytes - return int(to_hex(val), 16) - elif isinstance(val, type("".encode("L1").decode("L1"))): # hex-ustr - return int(val, 16) - elif isnumber(val): # int/long - return val # so we can use a bytes[x] in P2 or P3 - else: - raise Exception("to_dec() requires bytes, hex-ustr or [bin-ustr]") + """convert bytes, hex-ustr or [bin-ustr] to decimal int/long""" + if isinstance(val, list): # [bin-ustr] + return int(val[0], 2) + elif isinstance(val, bytes): # bytes + return int(to_hex(val), 16) + elif isinstance(val, type("".encode("L1").decode("L1"))): # hex-ustr + return int(val, 16) + elif isnumber(val): # int/long + return val # so we can use a bytes[x] in P2 or P3 + else: + raise Exception("to_dec() requires bytes, hex-ustr or [bin-ustr]") def to_bin(val): - """convert bytes, hex-ustr, or int/long to bin-ustr""" - if isinstance(val, bytes): # bytes - return (bin(to_dec(to_hex(val))))[2:].encode("L1").decode("L1") - elif isinstance(val, type("".encode("L1").decode("L1"))): # hex-ustr - return (bin(int(val, 16)))[2:].encode("L1").decode("L1") - elif isnumber(val): # int/long - return (bin(val))[2:].encode("L1").decode("L1") - else: - raise Exception("to_bin() requires bytes, hex-ustr, or int/long") + """convert bytes, hex-ustr, or int/long to bin-ustr""" + if isinstance(val, bytes): # bytes + return (bin(to_dec(to_hex(val))))[2:].encode("L1").decode("L1") + elif isinstance(val, type("".encode("L1").decode("L1"))): # hex-ustr + return (bin(int(val, 16)))[2:].encode("L1").decode("L1") + elif isnumber(val): # int/long + return (bin(val))[2:].encode("L1").decode("L1") + else: + raise Exception("to_bin() requires bytes, hex-ustr, or int/long") def to_bytes(val): - """converts hex-ustr, int/long, or [bin-ustr] to bytes""" - from binascii import a2b_hex - if isinstance(val, list): # [bin-ustr] - val = to_hex(val[0]) - if isnumber(val): # int/long - val = to_hex(val) - if isinstance(val, type("".encode("L1").decode("L1"))): # hex-ustr - return a2b_hex(bytes(val.encode("L1"))) # works on both P2 and P3 - elif isinstance(val, bytes): # so we can use a bytes[x] in P2 or P3 - return val - else: - raise Exception( - "to_bytes() requires hex-ustr, int/long, or [bin-ustr]") + """converts hex-ustr, int/long, or [bin-ustr] to bytes""" + from binascii import a2b_hex + if isinstance(val, list): # [bin-ustr] + val = to_hex(val[0]) + if isnumber(val): # int/long + val = to_hex(val) + if isinstance(val, type("".encode("L1").decode("L1"))): # hex-ustr + return a2b_hex(bytes(val.encode("L1"))) # works on both P2 and P3 + elif isinstance(val, bytes): # so we can use a bytes[x] in P2 or P3 + return val + else: + raise Exception( + "to_bytes() requires hex-ustr, int/long, or [bin-ustr]") def shift(items): - """Shift list items to left, losing the first item. + """Shift list items to left, losing the first item. - in : list - out: list - """ - for i in range(0, (len(items)-1)): - items[i] = items[i+1] - del items[-1] - return items + in : list + out: list + """ + for i in range(0, (len(items)-1)): + items[i] = items[i+1] + del items[-1] + return items def s(string): - """Perform local variable substution, e.g. 'total: {num} items'""" - # http://stackoverflow.com/questions/2960772/ - # putting-a-variable-inside-a-string-python - # http://stackoverflow.com/questions/6618795/ - # get-locals-from-calling-namespace-in-python - import inspect - frame = inspect.currentframe() - try: - rVal = string.format(**frame.f_back.f_locals) - finally: - del frame - return rVal + """Perform local variable substution, e.g. 'total: {num} items'""" + # http://stackoverflow.com/questions/2960772/ + # putting-a-variable-inside-a-string-python + # http://stackoverflow.com/questions/6618795/ + # get-locals-from-calling-namespace-in-python + import inspect + frame = inspect.currentframe() + try: + rVal = string.format(**frame.f_back.f_locals) + finally: + del frame + return rVal def get_object_names(cls, include_subclasses=True): - object_names = [] - for (this_object_name, this_object_id) in list(globals().items()): - if include_subclasses: - if isinstance(this_object_id, cls): - object_names.append(this_object_name) - else: - if type(this_object_id) is cls: - object_names.append(this_object_name) - return object_names + object_names = [] + for (this_object_name, this_object_id) in list(globals().items()): + if include_subclasses: + if isinstance(this_object_id, cls): + object_names.append(this_object_name) + else: + if type(this_object_id) is cls: + object_names.append(this_object_name) + return object_names def touch(filePath, modTime=None): - # http://stackoverflow.com/questions/1158076/implement-touch-using-python - # print(filePath) - import os - if (os.name == "nt"): - if filePath[-1] == ".": filePath += "-" - filePath = filePath.replace("./", ".-/") - with open(filePath, "ab"): - os.utime(filePath, (None if (modTime is None) else (modTime, modTime))) + # http://stackoverflow.com/questions/1158076/implement-touch-using-python + # print(filePath) + import os + if (os.name == "nt"): + if filePath[-1] == ".": filePath += "-" + filePath = filePath.replace("./", ".-/") + with open(filePath, "ab"): + os.utime(filePath, (None if (modTime is None) else (modTime, modTime))) def mkdir(dirPath): - import os - if (os.name == "nt"): - if dirPath[-1] == ".": dirPath += "-" - dirPath = dirPath.replace("./", ".-/") - try: - os.mkdir(dirPath) - except FileExistsError: - pass + import os + if (os.name == "nt"): + if dirPath[-1] == ".": dirPath += "-" + dirPath = dirPath.replace("./", ".-/") + try: + os.mkdir(dirPath) + except FileExistsError: + pass def makedirs(dirPath): - import os - if (os.name == "nt"): - if dirPath[-1] == ".": dirPath += "-" - dirPath = dirPath.replace("./", ".-/") - try: - os.makedirs(dirPath) - except OSError as e: - if (e.errno != errno.EEXIST): - raise + import os + if (os.name == "nt"): + if dirPath[-1] == ".": dirPath += "-" + dirPath = dirPath.replace("./", ".-/") + try: + os.makedirs(dirPath) + except OSError as e: + if (e.errno != errno.EEXIST): + raise def loadFile(filePath): - import os - if (os.name == "nt"): - if filePath[-1] == ".": filePath += "-" - filePath = filePath.replace("./", ".-/") - with open(filePath, "rb") as imageHandle: - return imageHandle.read() + import os + if (os.name == "nt"): + if filePath[-1] == ".": filePath += "-" + filePath = filePath.replace("./", ".-/") + with open(filePath, "rb") as imageHandle: + return imageHandle.read() def saveFile(filePath, fileData): - import os - if (os.name == "nt"): - if filePath[-1] == ".": filePath += "-" - filePath = filePath.replace("./", ".-/") - with open(filePath, "wb") as imageHandle: - imageHandle.write(fileData) + import os + if (os.name == "nt"): + if filePath[-1] == ".": filePath += "-" + filePath = filePath.replace("./", ".-/") + with open(filePath, "wb") as imageHandle: + imageHandle.write(fileData) def isnumber(number): - try: # make sure it's not a string - len(number) - return False - except TypeError: - pass - try: - int(number) - except ValueError: - return False - return True + try: # make sure it's not a string + len(number) + return False + except TypeError: + pass + try: + int(number) + except ValueError: + return False + return True #---- end IvanX general purpose functions ----# @@ -1099,189 +1099,189 @@ args = sys.argv while True: # breaks when there are no more arguments starting with dash - if (len(args) == 1): - usage() + if (len(args) == 1): + usage() - if (slyce(args[1],0,1) != "-"): - break + if (slyce(args[1],0,1) != "-"): + break - if (args[1] == "-s"): - g.nomsg = 1 - args = args[1:] #shift + if (args[1] == "-s"): + g.nomsg = 1 + args = args[1:] #shift - elif (args[1] == "-n"): - g.nodir = 1 - args = args[1:] #shift + elif (args[1] == "-n"): + g.nodir = 1 + args = args[1:] #shift - elif (args[1] == "-uc"): - g.UC = 1 - args = args[1:] #shift + elif (args[1] == "-uc"): + g.UC = 1 + args = args[1:] #shift - elif (args[1] == "-ad"): - g.AD = 1 - g.PNAME = 1 - args = args[1:] #shift + elif (args[1] == "-ad"): + g.AD = 1 + g.PNAME = 1 + args = args[1:] #shift - elif (args[1] == "-shk"): - g.SHK = 1 - args = args[1:] #shift + elif (args[1] == "-shk"): + g.SHK = 1 + args = args[1:] #shift - elif (args[1] == "-pro"): - g.PNAME = 1 - args = args[1:] #shift + elif (args[1] == "-pro"): + g.PNAME = 1 + args = args[1:] #shift - elif (args[1] == "-e"): - g.EX = 1 - g.PNAME = 1 - args = args[1:] #shift + elif (args[1] == "-e"): + g.EX = 1 + g.PNAME = 1 + args = args[1:] #shift - elif (args[1] == "-cat"): - g.CAT = 1 - args = args[1:] #shift + elif (args[1] == "-cat"): + g.CAT = 1 + args = args[1:] #shift - else: - usage() + else: + usage() if g.EX: - if g.AD: usage() + if g.AD: usage() if g.AD: - if g.EX: usage() + if g.EX: usage() if g.CAT: - if not (len(args) == 2): usage() + if not (len(args) == 2): usage() else: - if not ((len(args) == 3) or (len(args) == 4)): usage() + if not ((len(args) == 3) or (len(args) == 4)): usage() g.imageFile = args[1] if not os.path.isfile(g.imageFile): - print("Image/archive file \"" + g.imageFile + "\" was not found.") - quitNow(2) + print("Image/archive file \"" + g.imageFile + "\" was not found.") + quitNow(2) # automatically set ShrinkIt mode if extension suggests it if (g.SHK or - g.imageFile[-3:].lower() == "shk" or - g.imageFile[-3:].lower() == "sdk" or - g.imageFile[-3:].lower() == "bxy"): - if (os.name == "nt"): - print("ShrinkIt archives cannot be extracted on Windows.") - quitNow(2) - else: - try: - with open(os.devnull, "w") as fnull: - subprocess.call("nulib2", stdout = fnull, stderr = fnull) - g.SHK=1 - except Exception: - print("Nulib2 is not available; not expanding ShrinkIt archive.") - quitNow(2) + g.imageFile[-3:].lower() == "shk" or + g.imageFile[-3:].lower() == "sdk" or + g.imageFile[-3:].lower() == "bxy"): + if (os.name == "nt"): + print("ShrinkIt archives cannot be extracted on Windows.") + quitNow(2) + else: + try: + with open(os.devnull, "w") as fnull: + subprocess.call("nulib2", stdout = fnull, stderr = fnull) + g.SHK=1 + except Exception: + print("Nulib2 is not available; not expanding ShrinkIt archive.") + quitNow(2) if (len(args) == 4): - g.extractFile = args[2] + g.extractFile = args[2] if g.extractFile: - targetPath = args[3] - if os.path.isdir(targetPath): - g.targetDir = targetPath - elif (targetPath.rsplit("/", 1) > 1): - g.targetDir = targetPath.rsplit("/", 1)[0] - g.targetName = targetPath.rsplit("/", 1)[1] - if not os.path.isdir(g.targetDir): - print("Target directory not found.") - quitNow(2) + targetPath = args[3] + if os.path.isdir(targetPath): + g.targetDir = targetPath + elif (targetPath.rsplit("/", 1) > 1): + g.targetDir = targetPath.rsplit("/", 1)[0] + g.targetName = targetPath.rsplit("/", 1)[1] + if not os.path.isdir(g.targetDir): + print("Target directory not found.") + quitNow(2) else: - if not g.CAT: - if not os.path.isdir(args[2]): - print("Target directory not found.") - quitNow(2) + if not g.CAT: + if not os.path.isdir(args[2]): + print("Target directory not found.") + quitNow(2) if g.SHK: - g.PNAME = 0 - if not g.CAT: - targetDir = (args[3] if g.extractFile else args[2]) - unshkdir = ('/tmp' + "/cppo-" + str(uuid.uuid4())) - makedirs(unshkdir) - result = os.system("/bin/bash -c 'cd " + unshkdir + "; " + - "result=$(nulib2 -xse " + os.path.abspath(g.imageFile) + - ((" " + args[2].replace('/', ':')) - if g.extractFile else "") + " 2> /dev/null); " + - "if [[ $result == \"Failed.\" ]]; then exit 3; " + - "else if grep -q \"no records match\" <<< \"$result\"" + - " > /dev/null; then exit 2; else exit 0; fi; fi'") - if (result == 512): - print( - "File not found in ShrinkIt archive. Try cppo -cat to get the path,") - print(" and omit any leading slash or colon.") - quitNow(1) - elif (result != 0): - print("ShrinkIt archive is invalid, or some other problem happened.") - quitNow(1) - if g.extractFile: - g.extractFile = g.extractFile.replace(':', '/') - extractPath = (unshkdir + "/" + g.extractFile) - extractPathDir = os.path.dirname(extractPath) - # move the extracted file to the root - newunshkdir = ('/tmp' + "/cppo-" + str(uuid.uuid4())) - makedirs(newunshkdir) - for filename in os.listdir(extractPathDir): - shutil.move(extractPathDir + "/" + filename, newunshkdir) - shutil.rmtree(unshkdir) - unshkdir = newunshkdir + g.PNAME = 0 + if not g.CAT: + targetDir = (args[3] if g.extractFile else args[2]) + unshkdir = ('/tmp' + "/cppo-" + str(uuid.uuid4())) + makedirs(unshkdir) + result = os.system("/bin/bash -c 'cd " + unshkdir + "; " + + "result=$(nulib2 -xse " + os.path.abspath(g.imageFile) + + ((" " + args[2].replace('/', ':')) + if g.extractFile else "") + " 2> /dev/null); " + + "if [[ $result == \"Failed.\" ]]; then exit 3; " + + "else if grep -q \"no records match\" <<< \"$result\"" + + " > /dev/null; then exit 2; else exit 0; fi; fi'") + if (result == 512): + print( + "File not found in ShrinkIt archive. Try cppo -cat to get the path,") + print(" and omit any leading slash or colon.") + quitNow(1) + elif (result != 0): + print("ShrinkIt archive is invalid, or some other problem happened.") + quitNow(1) + if g.extractFile: + g.extractFile = g.extractFile.replace(':', '/') + extractPath = (unshkdir + "/" + g.extractFile) + extractPathDir = os.path.dirname(extractPath) + # move the extracted file to the root + newunshkdir = ('/tmp' + "/cppo-" + str(uuid.uuid4())) + makedirs(newunshkdir) + for filename in os.listdir(extractPathDir): + shutil.move(extractPathDir + "/" + filename, newunshkdir) + shutil.rmtree(unshkdir) + unshkdir = newunshkdir - fileNames = [name for name in sorted(os.listdir(unshkdir)) - if not name.startswith(".")] - if g.nodir: # extract in place from "-n" - curDir = True - elif (len(fileNames) == 1 and - os.path.isdir(unshkdir + "/" + fileNames[0])): - curDir = True # only one folder at top level, so extract in place - volumeName = toProdosName(fileNames[0]) - elif (len(fileNames) == 1 and # disk image, so extract in place - fileNames[0][-1:] == "i"): - curDir = True - volumeName = toProdosName(fileNames[0].split("#")[0]) - else: # extract in folder based on disk image name - curDir = False - volumeName = toProdosName(os.path.basename(g.imageFile)) - if (volumeName[-4:].lower() == ".shk" or - volumeName[-4:].lower() == ".sdk" or - volumeName[-4:].lower() == ".bxy"): - volumeName = volumeName[0:-4] - if not g.CAT and not curDir and not g.extractFile: - print("Extracting into " + volumeName) - # recursively process unshrunk archive hierarchy - for dirName, subdirList, fileList in os.walk(unshkdir): - subdirList.sort() - if not g.CAT: - g.targetDir = (targetDir + ("" if curDir else ("/" + volumeName)) + - ("/" if (dirName.count('/') > 2) else "") + - ("/".join(dirName.split('/')[3:]))) # chop tempdir - if g.extractFile: # solo item, so don't put it in the tree - g.targetDir = targetDir - if g.UC: - g.targetDir = g.targetDir.upper() - g.ADdir = (g.targetDir + "/.AppleDouble") - makedirs(g.targetDir) - if g.AD: - makedirs(g.ADdir) - for fname in sorted(fileList): - if (fname[-1:] == "i"): - # disk image; rename to include suffix and correct type/auxtype - imagePath = os.path.join(dirName, fname).split("#")[0] - new_name = (imagePath + - ("" if (imagePath.lower().endswith(".po") or - imagePath.lower().endswith(".hdv")) - else ".PO") + "#e00005") - os.rename(os.path.join(dirName, fname), new_name) - fname = os.path.basename(new_name) - g.shk_hasrf = False - rfork = False - if (fname[-1:] == "r" and - os.path.isfile(os.path.join(dirName, fname[:-1]))): - rfork = True - elif (os.path.isfile(os.path.join(dirName, (fname + "r")))): - g.shk_hasrf = True - if not rfork: - processEntry(dirName, fname) - shutil.rmtree(unshkdir, True) - quitNow(0) + fileNames = [name for name in sorted(os.listdir(unshkdir)) + if not name.startswith(".")] + if g.nodir: # extract in place from "-n" + curDir = True + elif (len(fileNames) == 1 and + os.path.isdir(unshkdir + "/" + fileNames[0])): + curDir = True # only one folder at top level, so extract in place + volumeName = toProdosName(fileNames[0]) + elif (len(fileNames) == 1 and # disk image, so extract in place + fileNames[0][-1:] == "i"): + curDir = True + volumeName = toProdosName(fileNames[0].split("#")[0]) + else: # extract in folder based on disk image name + curDir = False + volumeName = toProdosName(os.path.basename(g.imageFile)) + if (volumeName[-4:].lower() == ".shk" or + volumeName[-4:].lower() == ".sdk" or + volumeName[-4:].lower() == ".bxy"): + volumeName = volumeName[0:-4] + if not g.CAT and not curDir and not g.extractFile: + print("Extracting into " + volumeName) + # recursively process unshrunk archive hierarchy + for dirName, subdirList, fileList in os.walk(unshkdir): + subdirList.sort() + if not g.CAT: + g.targetDir = (targetDir + ("" if curDir else ("/" + volumeName)) + + ("/" if (dirName.count('/') > 2) else "") + + ("/".join(dirName.split('/')[3:]))) # chop tempdir + if g.extractFile: # solo item, so don't put it in the tree + g.targetDir = targetDir + if g.UC: + g.targetDir = g.targetDir.upper() + g.ADdir = (g.targetDir + "/.AppleDouble") + makedirs(g.targetDir) + if g.AD: + makedirs(g.ADdir) + for fname in sorted(fileList): + if (fname[-1:] == "i"): + # disk image; rename to include suffix and correct type/auxtype + imagePath = os.path.join(dirName, fname).split("#")[0] + new_name = (imagePath + + ("" if (imagePath.lower().endswith(".po") or + imagePath.lower().endswith(".hdv")) + else ".PO") + "#e00005") + os.rename(os.path.join(dirName, fname), new_name) + fname = os.path.basename(new_name) + g.shk_hasrf = False + rfork = False + if (fname[-1:] == "r" and + os.path.isfile(os.path.join(dirName, fname[:-1]))): + rfork = True + elif (os.path.isfile(os.path.join(dirName, (fname + "r")))): + g.shk_hasrf = True + if not rfork: + processEntry(dirName, fname) + shutil.rmtree(unshkdir, True) + quitNow(0) # end script if SHK @@ -1289,96 +1289,96 @@ g.imageData = loadFile(g.imageFile) # detect if image is 2mg and remove 64-byte header if so if (g.imageFile.lower().endswith(".2mg") or - g.imageFile.lower().endswith(".2img")): - g.imageData = g.imageData[64:] + g.imageFile.lower().endswith(".2img")): + g.imageData = g.imageData[64:] # handle 140K disk image if (len(g.imageData) == 143360): - #print("140K disk") - prodosDisk = 0 - fixOrder = 0 - # is it ProDOS? - if (to_hex(readchars(g.imageData, ts(0,0)+0, 4)) == '0138b003'): - #print("detected ProDOS by boot block") - if (readchars(g.imageData, ts(0,1)+3, 6) == b'PRODOS'): - prodosDisk = 1 - #print("order OK (PO)") - elif (readchars(g.imageData, ts(0,14)+3, 6) == b'PRODOS'): - #print("order needs fixing (DO)") - prodosDisk = 1 - fixOrder = 1 - # is it DOS 3.3? - else: - #print("it's not ProDOS") - if (readcharDec(g.imageData, ts(17,0)+3) == 3): - vtocT = readcharDec(g.imageData, ts(17,0)+1) - vtocS = readcharDec(g.imageData, ts(17,0)+2) - if (vtocT<35 and vtocS<16): - #print("it's DOS 3.3") - g.D33 = 1 - # it's DOS 3.3; check sector order next - if (readcharDec(g.imageData, ts(17,14)+2) != 13): - #print("order needs fixing (PO)") - fixOrder = 1 - #else: # remove this - # print("order OK (DO)") - # pass - # fall back on disk extension if weird boot block (e.g. AppleCommander) - if not prodosDisk and not g.D33: - #print("format and ordering unknown, checking extension") - if (g.imageFile.lower().endswith(".dsk") or - g.imageFile.lower().endswith(".do")): - fixOrder = 1 - # print("extension indicates DO, changing to PO") - if fixOrder: - #print("fixing order") - # for each track, - # read each sector in the right sequence to make - # valid ProDOS blocks (sector pairs) - imageDataFixed = bytearray(143360) - for t in range(0, 35): - for s in [0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15]: - writechars(imageDataFixed, - ts(t,((15-s) if (s%15) else s)), - readchars(g.imageData, ts(t,s), 256)) - g.imageData = bytes(imageDataFixed) - #print("saving fixed order file as outfile.dsk") - #saveFile("outfile.dsk", g.imageData) - #print("saved") + #print("140K disk") + prodosDisk = 0 + fixOrder = 0 + # is it ProDOS? + if (to_hex(readchars(g.imageData, ts(0,0)+0, 4)) == '0138b003'): + #print("detected ProDOS by boot block") + if (readchars(g.imageData, ts(0,1)+3, 6) == b'PRODOS'): + prodosDisk = 1 + #print("order OK (PO)") + elif (readchars(g.imageData, ts(0,14)+3, 6) == b'PRODOS'): + #print("order needs fixing (DO)") + prodosDisk = 1 + fixOrder = 1 + # is it DOS 3.3? + else: + #print("it's not ProDOS") + if (readcharDec(g.imageData, ts(17,0)+3) == 3): + vtocT = readcharDec(g.imageData, ts(17,0)+1) + vtocS = readcharDec(g.imageData, ts(17,0)+2) + if (vtocT<35 and vtocS<16): + #print("it's DOS 3.3") + g.D33 = 1 + # it's DOS 3.3; check sector order next + if (readcharDec(g.imageData, ts(17,14)+2) != 13): + #print("order needs fixing (PO)") + fixOrder = 1 + #else: # remove this + # print("order OK (DO)") + # pass + # fall back on disk extension if weird boot block (e.g. AppleCommander) + if not prodosDisk and not g.D33: + #print("format and ordering unknown, checking extension") + if (g.imageFile.lower().endswith(".dsk") or + g.imageFile.lower().endswith(".do")): + fixOrder = 1 + # print("extension indicates DO, changing to PO") + if fixOrder: + #print("fixing order") + # for each track, + # read each sector in the right sequence to make + # valid ProDOS blocks (sector pairs) + imageDataFixed = bytearray(143360) + for t in range(0, 35): + for s in [0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15]: + writechars(imageDataFixed, + ts(t,((15-s) if (s%15) else s)), + readchars(g.imageData, ts(t,s), 256)) + g.imageData = bytes(imageDataFixed) + #print("saving fixed order file as outfile.dsk") + #saveFile("outfile.dsk", g.imageData) + #print("saved") - if not prodosDisk and not g.D33: - print("Warning: Unable to determine disk format, assuming ProDOS.") + if not prodosDisk and not g.D33: + print("Warning: Unable to determine disk format, assuming ProDOS.") # enforce leading slash if ProDOS if (not g.SHK and - not g.D33 and - g.extractFile and - (slyce(args[2],0,1) != "/") and - (slyce(args[2],0,1) != ":")): - usage() + not g.D33 and + g.extractFile and + (slyce(args[2],0,1) != "/") and + (slyce(args[2],0,1) != ":")): + usage() if g.D33: - diskName = os.path.basename(g.imageFile) - if (diskName[-4:].lower() == ".dsk" or - diskName[-3:].lower() == ".do" or - diskName[-3:].lower() == ".po"): - diskName = os.path.splitext(diskName)[0] - if g.PNAME: - diskName = toProdosName(diskName) - if not g.CAT: - g.targetDir = (args[3] if g.extractFile - else (args[2] + "/" + diskName)) - g.ADdir = (g.targetDir + "/.AppleDouble") - makedirs(g.targetDir) - if g.AD: - makedirs(g.ADdir) - if not g.extractFile: - print("Extracting into " + diskName) - processDir([readcharDec(g.imageData, ts(17,0)+1), - readcharDec(g.imageData, ts(17,0)+2)]) - if g.extractFile: - print("ProDOS file not found within image file.") - quitNow(0) + diskName = os.path.basename(g.imageFile) + if (diskName[-4:].lower() == ".dsk" or + diskName[-3:].lower() == ".do" or + diskName[-3:].lower() == ".po"): + diskName = os.path.splitext(diskName)[0] + if g.PNAME: + diskName = toProdosName(diskName) + if not g.CAT: + g.targetDir = (args[3] if g.extractFile + else (args[2] + "/" + diskName)) + g.ADdir = (g.targetDir + "/.AppleDouble") + makedirs(g.targetDir) + if g.AD: + makedirs(g.ADdir) + if not g.extractFile: + print("Extracting into " + diskName) + processDir([readcharDec(g.imageData, ts(17,0)+1), + readcharDec(g.imageData, ts(17,0)+2)]) + if g.extractFile: + print("ProDOS file not found within image file.") + quitNow(0) # below: ProDOS @@ -1391,27 +1391,27 @@ g.PDOSPATH_INDEX = 0 g.PNAME = 0 if g.extractFile: - g.PDOSPATH = g.extractFile.replace(':', '/').split('/') - g.extractFile = None - if not g.PDOSPATH[0]: - g.PDOSPATH_INDEX += 1 - g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] - g.ADdir = (g.targetDir + "/.AppleDouble") - if not ((not g.AD) or os.path.isdir(g.ADdir)): - mkdir(g.ADdir) - processDir(2) - print("ProDOS file not found within image file.") - quitNow(2) + g.PDOSPATH = g.extractFile.replace(':', '/').split('/') + g.extractFile = None + if not g.PDOSPATH[0]: + g.PDOSPATH_INDEX += 1 + g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] + g.ADdir = (g.targetDir + "/.AppleDouble") + if not ((not g.AD) or os.path.isdir(g.ADdir)): + mkdir(g.ADdir) + processDir(2) + print("ProDOS file not found within image file.") + quitNow(2) else: - if not g.CAT: - # print(args[0], args[1], args[2]) - g.targetDir = (args[2] + "/" + getVolumeName().decode("L1")) - g.ADdir = (g.targetDir + "/.AppleDouble") - if not os.path.isdir(g.targetDir): - makedirs(g.targetDir) - if not ((not g.AD) or os.path.isdir(g.ADdir)): - makedirs(g.ADdir) - processDir(2) - if not g.CAT: - quitNow(0) + if not g.CAT: + # print(args[0], args[1], args[2]) + g.targetDir = (args[2] + "/" + getVolumeName().decode("L1")) + g.ADdir = (g.targetDir + "/.AppleDouble") + if not os.path.isdir(g.targetDir): + makedirs(g.targetDir) + if not ((not g.AD) or os.path.isdir(g.ADdir)): + makedirs(g.ADdir) + processDir(2) + if not g.CAT: + quitNow(0) diff --git a/scripts/tools/mkatinit.txt b/scripts/tools/mkatinit.txt index e6fad41..8c89dc1 100755 --- a/scripts/tools/mkatinit.txt +++ b/scripts/tools/mkatinit.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # mkatinit by Ivan Drucker, http://appleii.ivanx.com # not licensed; please modify and redistribute as you like @@ -27,12 +27,12 @@ decToChar () { # arg: decimal number from 0-255 # out: one character #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg - [[ $1 ]] || return 11 - [[ $2 ]] && return 8 - [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ - && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 - # args are valid - echo -n -e "\x$(printf %02X "$1")" + [[ $1 ]] || return 11 + [[ $2 ]] && return 8 + [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ + && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 + # args are valid + echo -n -e "\x$(printf %02X "$1")" } writechars () { @@ -44,18 +44,18 @@ writechars () { # out: nothing # exit: 8=extraneous arg, 11=missing arg1, # 13=missing stdin/arg3, 22=invalid arg2 - [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } - [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ - ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } - [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } - [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } - # args are valid - if [[ -t 0 ]]; then - echo -n "$3" | \ - dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null - else - dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null - fi + [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } + [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ + ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } + [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } + [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } + # args are valid + if [[ -t 0 ]]; then + echo -n "$3" | \ + dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null + else + dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null + fi } #---- mkatinit starts here @@ -74,49 +74,49 @@ echo usersfolder=1 while [ -n "$1" ] && [ "${1:0:1}" = '-' ]; do - flag="$1" - if [ $flag = "-gs" ]; then - gs=1 - shift - continue - elif [ $flag = "-d" ]; then - noprompt=1 - shift - continue - elif [ $flag = "-f" ]; then - overwrite=1 - shift - continue - elif [ $flag = "-g" ]; then - alsoguest=1 - shift - continue - elif [ $flag = "-c" ]; then - usersfolder=0 - shift - continue - else - badflag=1 - break - fi + flag="$1" + if [ $flag = "-gs" ]; then + gs=1 + shift + continue + elif [ $flag = "-d" ]; then + noprompt=1 + shift + continue + elif [ $flag = "-f" ]; then + overwrite=1 + shift + continue + elif [ $flag = "-g" ]; then + alsoguest=1 + shift + continue + elif [ $flag = "-c" ]; then + usersfolder=0 + shift + continue + else + badflag=1 + break + fi done if [ $usersfolder -eq 0 ] && [ -n "$alsoguest" ]; then - badflag=1 + badflag=1 fi if [ $badflag ]; then - echo "usage: mkatinit [-gs] [-d] [-f] [-g | -c] [|guest]" - echo - echo " should be the name of a netatalk user, or 'guest'" - echo "-gs sets the default ProDOS netboot system startup program and" - echo " prefix for GS/OS (if omitted, ProDOS 8 defaults are used)" - echo "-d use the default start program and prefix, without prompting" - echo "-f overwrite existing ATINIT file if present, without warning" - echo "-g create an ATINIT file for Guest as well as the specified user" - echo "-c write ATNIT to current directory instead of USERS hierarchy" - echo - exit + echo "usage: mkatinit [-gs] [-d] [-f] [-g | -c] [|guest]" + echo + echo " should be the name of a netatalk user, or 'guest'" + echo "-gs sets the default ProDOS netboot system startup program and" + echo " prefix for GS/OS (if omitted, ProDOS 8 defaults are used)" + echo "-d use the default start program and prefix, without prompting" + echo "-f overwrite existing ATINIT file if present, without warning" + echo "-g create an ATINIT file for Guest as well as the specified user" + echo "-c write ATNIT to current directory instead of USERS hierarchy" + echo + exit fi arg="$1" @@ -125,162 +125,162 @@ arg="$1" while : ; do - if [ ${#arg} -gt 32 ]; then - echo "User name is too long. Exiting with no action." - exit - elif [ -n "$arg" ]; then - if [ `echo $arg | tr '[:upper:]' '[:lower:]'` = "guest" ]; then - username='' - alsoguest= - if [[ ! $(grep -F -s $(ls -1 /home) /etc/default/netatalk) ]]; then - echo 'Warning: The AFPD_GUEST setting in /etc/default/netatalk is not assigned to a' - echo 'user with a folder in /home. Guest users may be able to boot over the network' - echo 'into ProDOS 8 for read-only access, but will not be able to boot into GS/OS.' - if [ $gs ]; then - echo ' Using ProDOS 8 defaults.' - gs= - else - echo - fi - echo - fi - else - username="$arg" - if [[ ! $(ls -1 /home | grep -F -s $username) ]]; then - echo "Warning: This username ($username) does not have a folder in /home. This user may" - echo "not be able to boot over the network into ProDOS 8 or GS/OS." - echo - fi - fi - if [ $gs ]; then - startprog="$gsstartprog" - prefix="$gsprefix" - fi - fi + if [ ${#arg} -gt 32 ]; then + echo "User name is too long. Exiting with no action." + exit + elif [ -n "$arg" ]; then + if [ `echo $arg | tr '[:upper:]' '[:lower:]'` = "guest" ]; then + username='' + alsoguest= + if [[ ! $(grep -F -s $(ls -1 /home) /etc/default/netatalk) ]]; then + echo 'Warning: The AFPD_GUEST setting in /etc/default/netatalk is not assigned to a' + echo 'user with a folder in /home. Guest users may be able to boot over the network' + echo 'into ProDOS 8 for read-only access, but will not be able to boot into GS/OS.' + if [ $gs ]; then + echo ' Using ProDOS 8 defaults.' + gs= + else + echo + fi + echo + fi + else + username="$arg" + if [[ ! $(ls -1 /home | grep -F -s $username) ]]; then + echo "Warning: This username ($username) does not have a folder in /home. This user may" + echo "not be able to boot over the network into ProDOS 8 or GS/OS." + echo + fi + fi + if [ $gs ]; then + startprog="$gsstartprog" + prefix="$gsprefix" + fi + fi - # make username all caps - username=`echo $username | tr '[:lower:]' '[:upper:]'` + # make username all caps + username=`echo $username | tr '[:lower:]' '[:upper:]'` - # prompt for folders - if [ ! $doalsoguest ] && [ ! $noprompt ]; then - while : ; do - echo "Enter the ProDOS path to the startup system program." - echo "default (CR to accept): $startprog" - read - if [ ${#REPLY} -gt 64 ]; then - continue - elif [ -n "$REPLY" ]; then - startprog="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" - echo - fi - break - done + # prompt for folders + if [ ! $doalsoguest ] && [ ! $noprompt ]; then + while : ; do + echo "Enter the ProDOS path to the startup system program." + echo "default (CR to accept): $startprog" + read + if [ ${#REPLY} -gt 64 ]; then + continue + elif [ -n "$REPLY" ]; then + startprog="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" + echo + fi + break + done - while : ; do - echo "Enter the initial ProDOS prefix:" - echo "default (CR to accept): $prefix" - read - if [ ${#REPLY} -gt 64 ]; then - continue - elif [ -n "$REPLY" ]; then - prefix="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" - echo - fi - break - done - fi + while : ; do + echo "Enter the initial ProDOS prefix:" + echo "default (CR to accept): $prefix" + read + if [ ${#REPLY} -gt 64 ]; then + continue + elif [ -n "$REPLY" ]; then + prefix="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" + echo + fi + break + done + fi - # create folders if needed - filepath="$PWD/$filename" + # create folders if needed + filepath="$PWD/$filename" - while [ $usersfolder -eq 1 ]; do - # create folders for ATINIT - while [ ! -d "$sharepath" ]; do - echo "Shared volume '$sharepath' not found. Edit mkatinit to change the default." - echo "Enter the local path to the netatalk shared volume used for netboot:" - read sharepath - done + while [ $usersfolder -eq 1 ]; do + # create folders for ATINIT + while [ ! -d "$sharepath" ]; do + echo "Shared volume '$sharepath' not found. Edit mkatinit to change the default." + echo "Enter the local path to the netatalk shared volume used for netboot:" + read sharepath + done - if [ ! -d "$sharepath/USERS" ]; then - mkdir "$sharepath/USERS" - if [ $? -ne 0 ]; then - break - fi - fi - if [ ! -d "$sharepath/USERS/$username" ]; then - mkdir "$sharepath/USERS/$username" - if [ $? -ne 0 ]; then - break - fi - fi - if [ ! -d "$sharepath/USERS/$username/SETUP" ]; then - mkdir "$sharepath/USERS/$username/SETUP" - if [ $? -ne 0 ]; then - break - fi - else - if [ ! -w "$sharepath/USERS/$username/SETUP" ]; then - break - fi - fi + if [ ! -d "$sharepath/USERS" ]; then + mkdir "$sharepath/USERS" + if [ $? -ne 0 ]; then + break + fi + fi + if [ ! -d "$sharepath/USERS/$username" ]; then + mkdir "$sharepath/USERS/$username" + if [ $? -ne 0 ]; then + break + fi + fi + if [ ! -d "$sharepath/USERS/$username/SETUP" ]; then + mkdir "$sharepath/USERS/$username/SETUP" + if [ $? -ne 0 ]; then + break + fi + else + if [ ! -w "$sharepath/USERS/$username/SETUP" ]; then + break + fi + fi - # we have a valid USERS folder target for ATINIT - filepath="$sharepath/USERS/$username/SETUP/$filename" - usersfolder=2 - done + # we have a valid USERS folder target for ATINIT + filepath="$sharepath/USERS/$username/SETUP/$filename" + usersfolder=2 + done - if [ $usersfolder -eq 1 ]; then - echo "Could not write to shared volume. Creating ATINIT in current directory." - if [ -n "$alsoguest" ]; then - echo "ATINIT for Guest user will not be created." - fi - echo - alsoguest= - fi + if [ $usersfolder -eq 1 ]; then + echo "Could not write to shared volume. Creating ATINIT in current directory." + if [ -n "$alsoguest" ]; then + echo "ATINIT for Guest user will not be created." + fi + echo + alsoguest= + fi - if [ ! $doalsoguest ]; then - echo "netboot start program: $startprog" - echo "netboot start prefix : $prefix" - echo - fi + if [ ! $doalsoguest ]; then + echo "netboot start program: $startprog" + echo "netboot start prefix : $prefix" + echo + fi - #remove ATINIT if present - if [ ! $overwrite ] && [ -f "$filepath" ]; then - echo -n "$filepath already exists. Overwrite? " - while read -s -n 1 > /dev/null 2>&1; do - if [ -z "$REPLY" ]; then - continue - elif [ "$REPLY" = "Y" ] || [ "$REPLY" = "y" ]; then - echo - break - elif [ "$REPLY" = "N" ] || [ "$REPLY" = "n" ]; then - echo - echo "Exiting with no action." - exit - fi - done - fi + #remove ATINIT if present + if [ ! $overwrite ] && [ -f "$filepath" ]; then + echo -n "$filepath already exists. Overwrite? " + while read -s -n 1 > /dev/null 2>&1; do + if [ -z "$REPLY" ]; then + continue + elif [ "$REPLY" = "Y" ] || [ "$REPLY" = "y" ]; then + echo + break + elif [ "$REPLY" = "N" ] || [ "$REPLY" = "n" ]; then + echo + echo "Exiting with no action." + exit + fi + done + fi - #write the file. start with zeroes - dd if=/dev/zero of="$filepath" bs=1 count=276 2> /dev/null - #put in startprog, prefix, username (first byte of each field is length) - # ( echo -n "${#startprog}" | awk '{printf("%c",$0);}'; echo -n "$startprog"; ) | dd of="$filepath" bs=1 seek=7 conv=notrunc 2> /dev/null - # ( echo -n "${#prefix}" | awk '{printf("%c",$0);}'; echo -n "$prefix"; ) | dd of="$filepath" bs=1 seek=78 conv=notrunc 2> /dev/null - # ( echo -n "${#username}" | awk '{printf("%c",$0);}'; echo -n "$username"; ) | dd of="$filepath" bs=1 seek=143 conv=notrunc 2> /dev/null - ( decToChar "${#startprog}"; echo -n "$startprog"; ) | writechars "$filepath" 7 - ( decToChar "${#prefix}"; echo -n "$prefix"; ) | writechars "$filepath" 78 - ( decToChar "${#username}"; echo -n "$username"; ) | writechars "$filepath" 143 + #write the file. start with zeroes + dd if=/dev/zero of="$filepath" bs=1 count=276 2> /dev/null + #put in startprog, prefix, username (first byte of each field is length) + # ( echo -n "${#startprog}" | awk '{printf("%c",$0);}'; echo -n "$startprog"; ) | dd of="$filepath" bs=1 seek=7 conv=notrunc 2> /dev/null + # ( echo -n "${#prefix}" | awk '{printf("%c",$0);}'; echo -n "$prefix"; ) | dd of="$filepath" bs=1 seek=78 conv=notrunc 2> /dev/null + # ( echo -n "${#username}" | awk '{printf("%c",$0);}'; echo -n "$username"; ) | dd of="$filepath" bs=1 seek=143 conv=notrunc 2> /dev/null + ( decToChar "${#startprog}"; echo -n "$startprog"; ) | writechars "$filepath" 7 + ( decToChar "${#prefix}"; echo -n "$prefix"; ) | writechars "$filepath" 78 + ( decToChar "${#username}"; echo -n "$username"; ) | writechars "$filepath" 143 - echo "Created $filepath" - if [ ! $alsoguest ]; then - break - fi + echo "Created $filepath" + if [ ! $alsoguest ]; then + break + fi - if [ $usersfolder -eq 2 ]; then - usersfolder=1 - fi - doalsoguest=1 - arg='guest' + if [ $usersfolder -eq 2 ]; then + usersfolder=1 + fi + doalsoguest=1 + arg='guest' done echo diff --git a/scripts/tools/mkvolinfo.txt b/scripts/tools/mkvolinfo.txt index f4811d4..94cd754 100755 --- a/scripts/tools/mkvolinfo.txt +++ b/scripts/tools/mkvolinfo.txt @@ -1,83 +1,83 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # mkvolinfo -- creates a (share)/.AppleDesktop/.volinfo file makeVolInfoFile () { - [[ -d $sharepath/.AppleDesktop ]] || mkdir $sharepath/.AppleDesktop - touch $volinfo - echo 'MAC_CHARSET:MAC_ROMAN' >> $volinfo - echo 'VOL_CHARSET:UTF8' >> $volinfo - echo 'ADOUBLE_VER:v2' >> $volinfo - echo 'CNIDBACKEND:dbd' >> $volinfo - echo 'CNIDDBDHOST:localhost' >> $volinfo - echo 'CNIDDBDPORT:4700' >> $volinfo - echo "CNID_DBPATH:$sharepath" >> $volinfo - echo 'VOLUME_OPTS:PRODOS CACHEID' >> $volinfo - if (( $mixedcase )); then - echo 'VOLCASEFOLD:' >> $volinfo - else - echo 'VOLCASEFOLD:MTOULOWER UTOMUPPER' >> $volinfo - fi - echo 'EXTATTRTYPE:AFPVOL_EA_AD' >> $volinfo - echo ".volinfo for $sharepath has been created." + [[ -d $sharepath/.AppleDesktop ]] || mkdir $sharepath/.AppleDesktop + touch $volinfo + echo 'MAC_CHARSET:MAC_ROMAN' >> $volinfo + echo 'VOL_CHARSET:UTF8' >> $volinfo + echo 'ADOUBLE_VER:v2' >> $volinfo + echo 'CNIDBACKEND:dbd' >> $volinfo + echo 'CNIDDBDHOST:localhost' >> $volinfo + echo 'CNIDDBDPORT:4700' >> $volinfo + echo "CNID_DBPATH:$sharepath" >> $volinfo + echo 'VOLUME_OPTS:PRODOS CACHEID' >> $volinfo + if (( $mixedcase )); then + echo 'VOLCASEFOLD:' >> $volinfo + else + echo 'VOLCASEFOLD:MTOULOWER UTOMUPPER' >> $volinfo + fi + echo 'EXTATTRTYPE:AFPVOL_EA_AD' >> $volinfo + echo ".volinfo for $sharepath has been created." } while [[ $1 == "-f" || $1 == "-c" ]]; do - if [[ $1 == "-f" ]]; then - force=1 - shift - fi + if [[ $1 == "-f" ]]; then + force=1 + shift + fi - if [[ $1 == "-c" ]]; then - mixedcase=1 - shift - fi + if [[ $1 == "-c" ]]; then + mixedcase=1 + shift + fi done if [[ ${1:0:1} == "-" ]]; then - echo "usage: mkvolinfo [-f] [-c] [shared volume path]" - echo - echo "-c will create the .volinfo file to specify no uppercase filename conversion" - echo "-f will create the .volinfo file without prompting, if none exists" - echo "If a path is specified, that is what is used, otherwise the last entry" - echo "in /usr/local/etc/netatalk/AppleVolumes.default is used." + echo "usage: mkvolinfo [-f] [-c] [shared volume path]" + echo + echo "-c will create the .volinfo file to specify no uppercase filename conversion" + echo "-f will create the .volinfo file without prompting, if none exists" + echo "If a path is specified, that is what is used, otherwise the last entry" + echo "in /usr/local/etc/netatalk/AppleVolumes.default is used." else - sudo true - if [[ $1 ]]; then - sharepath=$(readlink -m $1) - else - sharepath=$(grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) - fi + sudo true + if [[ $1 ]]; then + sharepath=$(readlink -m $1) + else + sharepath=$(grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) + fi - volinfo=$sharepath/.AppleDesktop/.volinfo + volinfo=$sharepath/.AppleDesktop/.volinfo - if [[ ! -d $sharepath ]]; then - echo "$sharepath does not exist." - else - if [[ -f $volinfo ]]; then - echo "$volinfo already exists." - else - if [[ $force ]]; then - makeVolInfoFile - else - echo "The .volinfo file is automatically generated when you first" - echo "log in from an AFP (Apple II or Mac) client machine." - echo "If you can't do this, you can create a .volinfo file now" - echo "based on assumed defaults; proceed with caution if you have" - echo "customized your AppleVolumes files." - echo - echo "If the path shown below is incorrect, you can specify" - echo "the path to your shared volume as an argument to mkvolinfo." - echo - echo -n "Make .volinfo for shared volume $sharepath now? " - read - if [[ ${REPLY:0:1} == "y" ]] || [[ ${REPLY:0:1} == "Y" ]]; then - makeVolInfoFile - fi - fi - fi - fi + if [[ ! -d $sharepath ]]; then + echo "$sharepath does not exist." + else + if [[ -f $volinfo ]]; then + echo "$volinfo already exists." + else + if [[ $force ]]; then + makeVolInfoFile + else + echo "The .volinfo file is automatically generated when you first" + echo "log in from an AFP (Apple II or Mac) client machine." + echo "If you can't do this, you can create a .volinfo file now" + echo "based on assumed defaults; proceed with caution if you have" + echo "customized your AppleVolumes files." + echo + echo "If the path shown below is incorrect, you can specify" + echo "the path to your shared volume as an argument to mkvolinfo." + echo + echo -n "Make .volinfo for shared volume $sharepath now? " + read + if [[ ${REPLY:0:1} == "y" ]] || [[ ${REPLY:0:1} == "Y" ]]; then + makeVolInfoFile + fi + fi + fi + fi fi diff --git a/setup/index.txt b/setup/index.txt index ceb2ab2..83dd6ec 100755 --- a/setup/index.txt +++ b/setup/index.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # A2SERVER master setup script, last update 17-Nov-15 # it downloads and executes several scripts related to the setup of @@ -30,7 +30,7 @@ isDebian= lsb_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ ( -f /etc/debian_version ) && ( $(cut -d . -f 1 < /etc/debian_version) -ge "7" ) ]] && isDebian=1 if [ -f /usr/local/etc/A2SERVER-version ]; then - installedVersion="$(cat /usr/local/etc/A2SERVER-version)" + installedVersion="$(cat /usr/local/etc/A2SERVER-version)" fi echo "A2SERVER version available: $a2serverVersion" echo "A2SERVER version installed: ${installedVersion:=None}" @@ -49,318 +49,318 @@ compileAlways= updateRasppleII= rm /tmp/a2server-* 2> /dev/null while [[ $1 ]]; do - if [[ $1 == "-r" ]]; then - shift - skipRepoUpdate="-r" - touch /tmp/a2server-packageReposUpdated - elif [[ $1 == "-i" ]]; then - shift - installAll="-i" - elif [[ $1 == "-y" ]]; then - shift - autoAnswerYes="-y" - touch /tmp/a2server-autoAnswerYes - elif [[ $1 == "-b" ]]; then - shift - setupNetBoot="-b" - touch /tmp/a2server-setupNetBoot - elif [[ $1 == "-w" ]]; then - shift - setupWindowsSharing="-w" - touch /tmp/a2server-setupWindowsSharing - elif [[ $1 == "-c" ]]; then - shift - compileAlways="-c" - touch /tmp/a2server-compileAlways - elif [[ $1 == "-os" || $1 == "os" ]]; then - # elif [[ ${1,,} == "rasppleii" || ${1,,} == "raspple" || ${1,,} == "rasappleii" || ${1,,} == "rasapple" || ${1,,} == "raspple2" || ${1,,} == "rasapple2" ]]; then - shift - updateRasppleII=1 - elif [[ $1 == "-v" ]]; then - shift - # Version was already printed - [[ $0 == "-bash" ]] && return 1 || exit 1 - elif [[ $1 ]]; then - echo "options:" - echo "-v: display installed and available versions, then exit" - echo "-i: reinstall A2SERVER software (but not Apple II software)" - echo "-y: auto-answer yes to all prompts" - echo "-r: don't update package repositories" - echo "-b: auto-setup network boot (use with -y)" - echo "-w: auto-setup Windows file sharing (use with -y)" - echo "-c: compile non-package items, rather than downloading binaries" - if [[ $isRpi ]]; then - echo "-os: update Raspbian OS, A2CLOUD, A2SERVER, and Apple II Pi" - fi - [[ $0 == "-bash" ]] && return 1 || exit 1 - fi + if [[ $1 == "-r" ]]; then + shift + skipRepoUpdate="-r" + touch /tmp/a2server-packageReposUpdated + elif [[ $1 == "-i" ]]; then + shift + installAll="-i" + elif [[ $1 == "-y" ]]; then + shift + autoAnswerYes="-y" + touch /tmp/a2server-autoAnswerYes + elif [[ $1 == "-b" ]]; then + shift + setupNetBoot="-b" + touch /tmp/a2server-setupNetBoot + elif [[ $1 == "-w" ]]; then + shift + setupWindowsSharing="-w" + touch /tmp/a2server-setupWindowsSharing + elif [[ $1 == "-c" ]]; then + shift + compileAlways="-c" + touch /tmp/a2server-compileAlways + elif [[ $1 == "-os" || $1 == "os" ]]; then + # elif [[ ${1,,} == "rasppleii" || ${1,,} == "raspple" || ${1,,} == "rasappleii" || ${1,,} == "rasapple" || ${1,,} == "raspple2" || ${1,,} == "rasapple2" ]]; then + shift + updateRasppleII=1 + elif [[ $1 == "-v" ]]; then + shift + # Version was already printed + [[ $0 == "-bash" ]] && return 1 || exit 1 + elif [[ $1 ]]; then + echo "options:" + echo "-v: display installed and available versions, then exit" + echo "-i: reinstall A2SERVER software (but not Apple II software)" + echo "-y: auto-answer yes to all prompts" + echo "-r: don't update package repositories" + echo "-b: auto-setup network boot (use with -y)" + echo "-w: auto-setup Windows file sharing (use with -y)" + echo "-c: compile non-package items, rather than downloading binaries" + if [[ $isRpi ]]; then + echo "-os: update Raspbian OS, A2CLOUD, A2SERVER, and Apple II Pi" + fi + [[ $0 == "-bash" ]] && return 1 || exit 1 + fi done if [[ $updateRasppleII ]]; then - echo "A2SERVER: Updating Raspple II (takes up to an hour)..." - wget -qO /tmp/raspbian-update "${A2SERVER_SCRIPT_URL}scripts/raspbian-update.txt" - source /tmp/raspbian-update a2cloud a2server $autoAnswerYes $skipRepoUpdate - [[ $0 == "-bash" ]] && return 0 || exit 0 + echo "A2SERVER: Updating Raspple II (takes up to an hour)..." + wget -qO /tmp/raspbian-update "${A2SERVER_SCRIPT_URL}scripts/raspbian-update.txt" + source /tmp/raspbian-update a2cloud a2server $autoAnswerYes $skipRepoUpdate + [[ $0 == "-bash" ]] && return 0 || exit 0 fi if { [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) < 110 )); }; then - echo - echo "WARNING: The current A2SERVER installer scripts haven't been tested for" - echo "updating the earlier version of A2SERVER that you have. A fresh install" - echo "is suggested. Continuing is not recommended and could make A2SERVER" - echo "no longer work properly, or cause data to be lost." + echo + echo "WARNING: The current A2SERVER installer scripts haven't been tested for" + echo "updating the earlier version of A2SERVER that you have. A fresh install" + echo "is suggested. Continuing is not recommended and could make A2SERVER" + echo "no longer work properly, or cause data to be lost." fi a2server_update=0 doSetup=1 if { [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) < 150 )); }; then - a2server_update=1 + a2server_update=1 fi unsupportedOS=1 if [[ $isRpi ]]; then #supported Raspbian? (16-Feb-15, 20-Jun-14, 09-Jan-14, etc) - fwhash=$(zcat /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | grep -m 1 'as of' | awk '{print $NF}') - fwsupported="-8aca5762- -462f3e3f476f7b6- -c32bc633039cd9- -9d34d0475f9- - -d4f5315cfac4e- -6f4a90c8cb8817f- -5dd9b4962e- -17c8799375- - -960832a6c2590635216c296b6ee0bebf67b21d50- - -2a329e0c7d8ea19c085bac5633aa4fccee0f21be-" - [[ "$fwsupported" == *-$fwhash-* ]] && unsupportedOS= - # [[ ($fwhash == "8aca5762") || ($fwhash == "462f3e3f476f7b6") || ($fwhash == "c32bc633039cd9") || ($fwhash == "9d34d0475f9") || ($fwhash == "d4f5315cfac4e") || ($fwhash == "6f4a90c8cb8817f") || ($fwhash == "5dd9b4962e") || ($fwhash == "17c8799375") ]] && unsupportedOS= + fwhash=$(zcat /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | grep -m 1 'as of' | awk '{print $NF}') + fwsupported="-8aca5762- -462f3e3f476f7b6- -c32bc633039cd9- -9d34d0475f9- + -d4f5315cfac4e- -6f4a90c8cb8817f- -5dd9b4962e- -17c8799375- + -960832a6c2590635216c296b6ee0bebf67b21d50- + -2a329e0c7d8ea19c085bac5633aa4fccee0f21be-" + [[ "$fwsupported" == *-$fwhash-* ]] && unsupportedOS= + # [[ ($fwhash == "8aca5762") || ($fwhash == "462f3e3f476f7b6") || ($fwhash == "c32bc633039cd9") || ($fwhash == "9d34d0475f9") || ($fwhash == "d4f5315cfac4e") || ($fwhash == "6f4a90c8cb8817f") || ($fwhash == "5dd9b4962e") || ($fwhash == "17c8799375") ]] && unsupportedOS= elif [[ $isDebian ]]; then # supported Debian? - debianVersion=$(cat /etc/debian_version) - debianSupported="-8.2- -7.9- -7.8- -7.6- -7.3-" - [[ $debianSupported == *-$debianVersion-* ]] && unsupportedOS= + debianVersion=$(cat /etc/debian_version) + debianSupported="-8.2- -7.9- -7.8- -7.6- -7.3-" + [[ $debianSupported == *-$debianVersion-* ]] && unsupportedOS= fi if [[ $unsupportedOS && $isRpi ]]; then - echo - echo "A2SERVER and its installer scripts have been tested on Raspbian Wheezy and" - echo "Jessie, though not this specific firmware version ($fwhash). Just FYI." - unsupportedOS= + echo + echo "A2SERVER and its installer scripts have been tested on Raspbian Wheezy and" + echo "Jessie, though not this specific firmware version ($fwhash). Just FYI." + unsupportedOS= elif [[ $unsupportedOS && $isDebian ]]; then - echo - echo "A2SERVER and its installer scripts have been tested on Debian 7 and 8," - echo "though not this specific point release ($debianVersion). Just FYI." - unsupportedOS= + echo + echo "A2SERVER and its installer scripts have been tested on Debian 7 and 8," + echo "though not this specific point release ($debianVersion). Just FYI." + unsupportedOS= fi if [[ $unsupportedOS ]]; then - echo - echo "WARNING: A2SERVER and its installer scripts have only been tested on" - echo "Debian and Raspbian. Continuing is probably fine, but might not be." - echo "Theoretical worst case would be your operating system no longer works" - echo "properly or data is lost, so consider backing up first." + echo + echo "WARNING: A2SERVER and its installer scripts have only been tested on" + echo "Debian and Raspbian. Continuing is probably fine, but might not be." + echo "Theoretical worst case would be your operating system no longer works" + echo "properly or data is lost, so consider backing up first." fi doSetup=1 if [[ $installAll || ! -f /usr/local/etc/a2server-help.txt ]] || (( $a2server_update )); then - echo - echo "Setting up A2SERVER will take up to 60 minutes, during which" - echo "you'll see a bunch of stuff spit out across the screen." - echo - if [[ ! $autoAnswerYes ]]; then - echo -n "Ready to set up A2SERVER? " - read - [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; doSetup=$(( 1 - $? )) - fi + echo + echo "Setting up A2SERVER will take up to 60 minutes, during which" + echo "you'll see a bunch of stuff spit out across the screen." + echo + if [[ ! $autoAnswerYes ]]; then + echo -n "Ready to set up A2SERVER? " + read + [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; doSetup=$(( 1 - $? )) + fi fi if (( $doSetup )); then - echo - echo "a2server-setup modifies files and performs actions as the root user." - echo "For details, visit http://ivanx.com/a2server." - echo - if [[ ! $autoAnswerYes ]]; then - echo -n "Continue? " - read - [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; doSetup=$(( 1 - $? )) - fi + echo + echo "a2server-setup modifies files and performs actions as the root user." + echo "For details, visit http://ivanx.com/a2server." + echo + if [[ ! $autoAnswerYes ]]; then + echo -n "Continue? " + read + [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; doSetup=$(( 1 - $? )) + fi - if (( $doSetup )); then + if (( $doSetup )); then - userPw=$(sudo grep "^$USER" /etc/shadow | cut -f 2 -d ':') - [[ $userPw == "$(echo 'apple2' | perl -e '$_ = ; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isApple2Pw=1 || isApple2Pw= - [[ $userPw == "$(echo 'raspberry' | perl -e '$_ = ; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isRaspberryPw=1 || isRaspberryPw= + userPw=$(sudo grep "^$USER" /etc/shadow | cut -f 2 -d ':') + [[ $userPw == "$(echo 'apple2' | perl -e '$_ = ; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isApple2Pw=1 || isApple2Pw= + [[ $userPw == "$(echo 'raspberry' | perl -e '$_ = ; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isRaspberryPw=1 || isRaspberryPw= - password="your password" - [[ $isApple2Pw ]] && password="'apple2'" - [[ $isRaspberryPw ]] && password="'raspberry'" + password="your password" + [[ $isApple2Pw ]] && password="'apple2'" + [[ $isRaspberryPw ]] && password="'raspberry'" - [[ $isRpi ]] && a2server="your Raspberry Pi" || a2server="A2SERVER" - if [[ ! $isApple2Pw && ! -f /usr/local/etc/A2SERVER-version ]]; then - if [[ ! $autoAnswerYes ]]; then - echo - echo "To ensure that all client computers are able to connect to" - echo "${a2server} using the same password, you probably want" - echo "to change your user password to 'apple2'." - echo - echo -n "Do you want to change the password for user '$USER' to 'apple2' now? " - read - fi - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - echo "A2SERVER: changing password for user '$USER' to 'apple2'..." - echo "$USER:apple2" | sudo chpasswd - fi - fi + [[ $isRpi ]] && a2server="your Raspberry Pi" || a2server="A2SERVER" + if [[ ! $isApple2Pw && ! -f /usr/local/etc/A2SERVER-version ]]; then + if [[ ! $autoAnswerYes ]]; then + echo + echo "To ensure that all client computers are able to connect to" + echo "${a2server} using the same password, you probably want" + echo "to change your user password to 'apple2'." + echo + echo -n "Do you want to change the password for user '$USER' to 'apple2' now? " + read + fi + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + echo "A2SERVER: changing password for user '$USER' to 'apple2'..." + echo "$USER:apple2" | sudo chpasswd + fi + fi - echo - echo "During this installation, enter ${password} if prompted for passwords." - echo + echo + echo "During this installation, enter ${password} if prompted for passwords." + echo - sudo true + sudo true - echo - echo "A2SERVER: Downloading scripts..." + echo + echo "A2SERVER: Downloading scripts..." - wget -q -O /tmp/1.storage "${scriptURL}scripts/a2server-1-storage.txt" - chmod ugo+x /tmp/1.storage + wget -q -O /tmp/1.storage "${scriptURL}scripts/a2server-1-storage.txt" + chmod ugo+x /tmp/1.storage - wget -q -O /tmp/2.tools "${scriptURL}scripts/a2server-2-tools.txt" - chmod ugo+x /tmp/2.tools + wget -q -O /tmp/2.tools "${scriptURL}scripts/a2server-2-tools.txt" + chmod ugo+x /tmp/2.tools - wget -q -O /tmp/3.sharing "${scriptURL}scripts/a2server-3-sharing.txt" - chmod ugo+x /tmp/3.sharing + wget -q -O /tmp/3.sharing "${scriptURL}scripts/a2server-3-sharing.txt" + chmod ugo+x /tmp/3.sharing - wget -q -O /tmp/5.netboot "${scriptURL}scripts/a2server-5-netboot.txt" - chmod ugo+x /tmp/5.netboot + wget -q -O /tmp/5.netboot "${scriptURL}scripts/a2server-5-netboot.txt" + chmod ugo+x /tmp/5.netboot - wget -q -O /tmp/6.samba "${scriptURL}scripts/a2server-6-samba.txt" - chmod ugo+x /tmp/6.samba + wget -q -O /tmp/6.samba "${scriptURL}scripts/a2server-6-samba.txt" + chmod ugo+x /tmp/6.samba - wget -q -O /tmp/7.console "${scriptURL}scripts/a2server-7-console.txt" - chmod ugo+x /tmp/7.console + wget -q -O /tmp/7.console "${scriptURL}scripts/a2server-7-console.txt" + chmod ugo+x /tmp/7.console - echo "A2SERVER: Scripts have been downloaded. Installing..." + echo "A2SERVER: Scripts have been downloaded. Installing..." - if [[ $installAll ]]; then - sudo rm /usr/local/etc/A2SERVER-version 2> /dev/null - sudo rm /usr/local/bin/nulib2 2> /dev/null - sudo rm /usr/local/bin/unar 2> /dev/null - sudo rm /usr/local/sbin/macipgw 2> /dev/null - sudo rm /usr/local/bin/ciopfs 2> /dev/null - sudo rm /usr/local/etc/netatalk/afppasswd 2> /dev/null - sudo rm /usr/local/etc/netatalk/a2boot/p8 /usr/local/etc/netatalk/a2boot/ProDOS16\ Image 2> /dev/null - fi + if [[ $installAll ]]; then + sudo rm /usr/local/etc/A2SERVER-version 2> /dev/null + sudo rm /usr/local/bin/nulib2 2> /dev/null + sudo rm /usr/local/bin/unar 2> /dev/null + sudo rm /usr/local/sbin/macipgw 2> /dev/null + sudo rm /usr/local/bin/ciopfs 2> /dev/null + sudo rm /usr/local/etc/netatalk/afppasswd 2> /dev/null + sudo rm /usr/local/etc/netatalk/a2boot/p8 /usr/local/etc/netatalk/a2boot/ProDOS16\ Image 2> /dev/null + fi - /tmp/1.storage - rm /tmp/1.storage - /tmp/2.tools - rm /tmp/2.tools - /tmp/3.sharing - rm /tmp/3.sharing - /tmp/5.netboot - rm /tmp/5.netboot - /tmp/6.samba - rm /tmp/6.samba - /tmp/7.console - rm /tmp/7.console - rm /tmp/a2server-packageReposUpdated &> /dev/null + /tmp/1.storage + rm /tmp/1.storage + /tmp/2.tools + rm /tmp/2.tools + /tmp/3.sharing + rm /tmp/3.sharing + /tmp/5.netboot + rm /tmp/5.netboot + /tmp/6.samba + rm /tmp/6.samba + /tmp/7.console + rm /tmp/7.console + rm /tmp/a2server-packageReposUpdated &> /dev/null - if [[ ! -f /usr/local/etc/A2SERVER-version ]] \ - || (( $(head -c 3 /usr/local/etc/A2SERVER-version) < ${a2serverVersion:0:3} )); then - echo "$a2serverVersion" | sudo tee /usr/local/etc/A2SERVER-version &> /dev/null - fi + if [[ ! -f /usr/local/etc/A2SERVER-version ]] \ + || (( $(head -c 3 /usr/local/etc/A2SERVER-version) < ${a2serverVersion:0:3} )); then + echo "$a2serverVersion" | sudo tee /usr/local/etc/A2SERVER-version &> /dev/null + fi - source /usr/local/etc/a2serverrc + source /usr/local/etc/a2serverrc - # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) - kernelRelease=$(uname -r) - kernelMajorRelease=$(cut -d '.' -f 1 <<< $kernelRelease) - kernelMinorRelease=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') + # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) + kernelRelease=$(uname -r) + kernelMajorRelease=$(cut -d '.' -f 1 <<< $kernelRelease) + kernelMinorRelease=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') - echo - # all done, see if AppleTalk is available and notify either way - if [[ $(ps aux | grep [a]talkd) ]]; then - echo "You now have a fully functional file server for Apple II clients." - echo "On an Apple IIe, it should be accessible via \"Log In\" on the" - echo "Workstation Card software. For IIgs users, it should be accessible" - echo "via the AppleShare control panel." - if [[ -f /srv/A2SERVER/A2FILES/System/Start.GS.OS ]]; then - echo - echo "You can network boot GS/OS." - echo "On a ROM 01 IIgs, set slot 1 (printer port), or slot 2 (modem port)" - echo "to Your Card, and slot 7 to AppleTalk, and Startup Slot to 7 or Scan." - echo "On a ROM 3 IIgs, set slot 1 or 2, and Startup Slot, to AppleTalk." - fi - if [[ -f /srv/A2SERVER/A2FILES/BASIC.System ]]; then - echo - echo "You can network boot ProDOS 8. On an Apple IIe, put your Workstation Card" - echo "in a slot above your disk controller card, or type PR#X with open-apple" - echo "held down, with X being the slot of your Workstation Card." - echo 'On a IIgs, press "8" during the initial procession of periods.' - fi - echo - echo "A2SERVER setup is complete! Go connect from your Apple II!" - echo - elif [[ -f /tmp/rpiUpdate ]]; then - echo "A2SERVER is now configured, but Apple II clients will not be able" - echo "to connect until you restart your Raspberry Pi." - echo - if [[ ! $autoAnswerYes ]]; then - echo -n "Restart now? " - read - fi - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - sudo shutdown -r now - echo - echo "A2SERVER: Preparing to restart..." - while :; do sleep 60; done - fi - rm /tmp/rpiUpdate - echo - elif [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -ge 12 && $kernelMinorRelease -le 15 ]]; then - echo "A2SERVER is now configured, but Apple II clients cannot connect" - echo "because of a kernel-crashing bug in Linux kernel 3.12 through 3.15." - echo "You have kernel version $kernelMajorRelease.$kernelMinorRelease." - echo "A2SERVER has disabled AppleTalk networking to prevent crashes." - echo "Please use kernel 3.11 or earlier, or kernel 3.16 or later." - echo - else - echo "A2SERVER is now configured, but Apple II clients cannot connect because" - echo "AppleTalk networking is unavailable. Please make sure that" - echo "your Linux distribution has a loadable AppleTalk kernel module or" - echo "has AppleTalk built into the kernel, and restart your server." - echo "Or, if you previously disabled AppleTalk in A2SERVER, re-enable it" - echo "by typing 'appletalk-on'." - echo - fi + echo + # all done, see if AppleTalk is available and notify either way + if [[ $(ps aux | grep [a]talkd) ]]; then + echo "You now have a fully functional file server for Apple II clients." + echo "On an Apple IIe, it should be accessible via \"Log In\" on the" + echo "Workstation Card software. For IIgs users, it should be accessible" + echo "via the AppleShare control panel." + if [[ -f /srv/A2SERVER/A2FILES/System/Start.GS.OS ]]; then + echo + echo "You can network boot GS/OS." + echo "On a ROM 01 IIgs, set slot 1 (printer port), or slot 2 (modem port)" + echo "to Your Card, and slot 7 to AppleTalk, and Startup Slot to 7 or Scan." + echo "On a ROM 3 IIgs, set slot 1 or 2, and Startup Slot, to AppleTalk." + fi + if [[ -f /srv/A2SERVER/A2FILES/BASIC.System ]]; then + echo + echo "You can network boot ProDOS 8. On an Apple IIe, put your Workstation Card" + echo "in a slot above your disk controller card, or type PR#X with open-apple" + echo "held down, with X being the slot of your Workstation Card." + echo 'On a IIgs, press "8" during the initial procession of periods.' + fi + echo + echo "A2SERVER setup is complete! Go connect from your Apple II!" + echo + elif [[ -f /tmp/rpiUpdate ]]; then + echo "A2SERVER is now configured, but Apple II clients will not be able" + echo "to connect until you restart your Raspberry Pi." + echo + if [[ ! $autoAnswerYes ]]; then + echo -n "Restart now? " + read + fi + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + sudo shutdown -r now + echo + echo "A2SERVER: Preparing to restart..." + while :; do sleep 60; done + fi + rm /tmp/rpiUpdate + echo + elif [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -ge 12 && $kernelMinorRelease -le 15 ]]; then + echo "A2SERVER is now configured, but Apple II clients cannot connect" + echo "because of a kernel-crashing bug in Linux kernel 3.12 through 3.15." + echo "You have kernel version $kernelMajorRelease.$kernelMinorRelease." + echo "A2SERVER has disabled AppleTalk networking to prevent crashes." + echo "Please use kernel 3.11 or earlier, or kernel 3.16 or later." + echo + else + echo "A2SERVER is now configured, but Apple II clients cannot connect because" + echo "AppleTalk networking is unavailable. Please make sure that" + echo "your Linux distribution has a loadable AppleTalk kernel module or" + echo "has AppleTalk built into the kernel, and restart your server." + echo "Or, if you previously disabled AppleTalk in A2SERVER, re-enable it" + echo "by typing 'appletalk-on'." + echo + fi - if [[ -f /tmp/noMacIP ]]; then - echo - echo "MacIP connections may be unavailable. If you know how, try" - echo "recompiling the AppleTalk kernel module with IPDDP options disabled." - echo - rm /tmp/noMacIP - fi + if [[ -f /tmp/noMacIP ]]; then + echo + echo "MacIP connections may be unavailable. If you know how, try" + echo "recompiling the AppleTalk kernel module with IPDDP options disabled." + echo + rm /tmp/noMacIP + fi - if [[ -f /tmp/singleUser ]]; then - if [[ ! $autoAnswerYes ]]; then - echo - echo "Your Raspberry Pi was started in single-user mode in order to" - echo -n "fix a problem. You should restart to operate normally. Restart now? " - read - fi - if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then - sudo shutdown -r now - echo - echo "A2SERVER: Preparing to restart..." - while :; do sleep 60; done - fi - rm /tmp/singleUser - echo - fi + if [[ -f /tmp/singleUser ]]; then + if [[ ! $autoAnswerYes ]]; then + echo + echo "Your Raspberry Pi was started in single-user mode in order to" + echo -n "fix a problem. You should restart to operate normally. Restart now? " + read + fi + if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then + sudo shutdown -r now + echo + echo "A2SERVER: Preparing to restart..." + while :; do sleep 60; done + fi + rm /tmp/singleUser + echo + fi - echo - echo "Type 'system-shutdown' to turn off A2SERVER." - echo "Type 'a2server-setup' to configure network boot." - echo "Type 'a2server-help' for a list of other commands." - fi + echo + echo "Type 'system-shutdown' to turn off A2SERVER." + echo "Type 'a2server-setup' to configure network boot." + echo "Type 'a2server-help' for a list of other commands." + fi fi unset a2server_update 2> /dev/null unset doSetup 2> /dev/null -rm /tmp/a2server-* 2> /dev/null -rm setup &> /dev/null +rm -f /tmp/a2server-* 2> /dev/null +rm -f setup &> /dev/null diff --git a/update/index.txt b/update/index.txt index 0d3a28f..619229d 100755 --- a/update/index.txt +++ b/update/index.txt @@ -1,5 +1,5 @@ #! /bin/bash -# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: +# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh: # Ensure URL we'll use ends in a / case "$A2SERVER_SCRIPT_URL" in @@ -10,17 +10,17 @@ esac currentVersion=$(wget -qO- "${scriptURL}setup/index.txt" | grep '^a2serverVersion' | cut -d '"' -f 2) if [[ -f /usr/local/etc/A2SERVER-version ]]; then - installedVersion=$(cat /usr/local/etc/A2SERVER-version) + installedVersion=$(cat /usr/local/etc/A2SERVER-version) else - installedVersion=100 + installedVersion=100 fi autoAnswerYes= for arg in $@; do - if [[ $arg == "-y" ]]; then - autoAnswerYes=1 - break - fi + if [[ $arg == "-y" ]]; then + autoAnswerYes=1 + break + fi done echo @@ -31,14 +31,14 @@ echo "installed version: ${installedVersion:0:1}.${installedVersion:1:1}.${insta echo "current version: ${currentVersion:0:1}.${currentVersion:1:1}.${currentVersion:2:1}" echo if [[ $autoAnswerYes ]]; then - REPLY="y" + REPLY="y" else - echo -n "Do you want to update (or reinstall) A2SERVER? " - read + echo -n "Do you want to update (or reinstall) A2SERVER? " + read fi if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then - # sudo rm /usr/local/etc/netatalk/a2boot/* &> /dev/null - wget -q -O /tmp/setup "${scriptURL}setup/index.txt"; source /tmp/setup -i "$@" + # sudo rm /usr/local/etc/netatalk/a2boot/* &> /dev/null + wget -q -O /tmp/setup "${scriptURL}setup/index.txt"; source /tmp/setup -i "$@" fi unset currentVersion 2> /dev/null