├── LICENSE.md ├── README.md ├── files ├── A2FILES-list.txt ├── dist │ └── getexternal.sh ├── macip-prefs.tgz ├── macipgw-start.sh.txt ├── macipgw.service.txt ├── netatalk-init.d-clean.txt ├── netatalkpatches.tar.gz ├── tash0.txt ├── tashrouter.py └── tashrouter.service.txt ├── fix └── fix.txt ├── scripts ├── a2server-1-storage.txt ├── a2server-2-tools.txt ├── a2server-3-sharing.txt ├── a2server-5-netboot.txt ├── a2server-6-samba.txt ├── a2server-7-console.txt ├── clock.patch.py ├── raspbian-update.txt └── tools │ ├── a2server-aliases.txt │ ├── a2server-help.txt │ ├── a2serverrc.txt │ ├── afpsync.txt │ ├── afptype.txt │ ├── cppo.txt │ ├── mkatinit.txt │ ├── mkvolinfo.txt │ └── netatalk-maketar.txt ├── setup └── index.txt └── update ├── devhistory.txt ├── index.txt └── versionhistory.txt /LICENSE.md: -------------------------------------------------------------------------------- 1 | License for A2SERVER 2 | ==================== 3 | 4 | A2SERVER 5 | 6 | Copyright (C) 2013-2015 Ivan Drucker 7 | 8 | The A2SERVER scripts themselves are written primarily by Ivan Drucker and 9 | released under the WTFPL version 2, which you may download from its web page 10 | at . This is essentially a public domain 11 | release, which doesn't extend to the other programs used by A2SERVER such as 12 | netatalk or the various Linux tools it installs. These have their own license 13 | terms and Copyrights. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A2SERVER 2 | AppleTalk server for Apple // computers developed by Ivan Drucker, with 3 | substantial rework and by T. Joseph Carter 4 | 5 | Documentation here is sparse for the moment; see [Ivan's site]() for 6 | information about A2SERVER and how it all works. There's a lot there and it's 7 | kind of evolved organically over the years just as the scripts themselves 8 | have, so it's going to be awhile before that information can be backfilled and 9 | perhaps organized into something you might call a user manual. 10 | 11 | Such a manual should not be considered a replacement for Ivan's organic online 12 | documentation--those contents themselves represent Apple // history, if a 13 | relatively modern piece of it. As such they should be preserved as they are. 14 | 15 | ## Developer note 16 | 17 | To use the scripts with a specific GitHub tag: 18 | ~~~ bash 19 | export A2SERVER_SCRIPT_URL=https://raw.githubusercontent.com/NJRoadfan/a2server/TAG_GOES_HERE/ 20 | export A2SERVER_BINARY_URL=${A2SERVER_SCRIPT_URL}files 21 | wget -O setup ${A2SERVER_SCRIPT_URL}setup/index.txt; source setup 22 | ~~~ 23 | 24 | Or, to use the scripts on your own server, including your local machine: 25 | 26 | ~~~ bash 27 | export A2SERVER_SCRIPT_URL=http://yoururl.com/ 28 | ~~~ 29 | 30 | To prevent needing to recompile various packages from source code during 31 | installation, a number of precompiled binary files are downloaded for Raspbian, 32 | Debian-x86, and Debian-amd64. If you wish to host these on your own server: 33 | 34 | ~~~ bash 35 | export A2SERVER_BINARY_URL=http://yoururl.com/files/ 36 | ~~~ 37 | 38 | You do not need to use a subdirectory called "files", or the same server, but 39 | that's the normal arrangement. The precompiled packages are available here: 40 | `http://appleii.ivanx.com/a2server/files/dist/a2serverbinaries.tar.gz` 41 | 42 | Several Apple II third-party binaries are downloaded during installation, as 43 | well as third-party source code if precompiled binaries are unavailable or 44 | you don't wish to use them. If you want these external dependencies locally 45 | during development, they need to go into a folder called "external" in 46 | the binaries URL, and that needs to contain folders called "appleii" and 47 | "source". To download all of these external packages, download and run the 48 | shell script at 49 | `http://appleii.ivanx.com/a2server/files/dist/getexternal.sh`. 50 | 51 | Once you have those: 52 | 53 | ~~~ bash 54 | export A2SERVER_NO_EXTERNAL=1 55 | ~~~ 56 | 57 | You may want to put the above exports into `~/.bashrc` or `~/.bash_profile`. 58 | 59 | If you want to host scripts locally installed on your own machine or another 60 | computer on your LAN, type the following, and export "http://localhost:8000/" 61 | or "http://lan.ip.address:8000/" for the above URL's. 62 | 63 | ~~~ 64 | python3 -m http.server 65 | ~~~ 66 | 67 | Once you're set, you can then run the following snippet to install A2SERVER: 68 | 69 | ~~~ 70 | wget -O setup ${A2SERVER_SCRIPT_URL}setup/index.txt; source setup 71 | ~~~ 72 | 73 | 74 | Offline install: 75 | 76 | Offline installs are no longer supported with A2SERVER 2.x. 77 | 78 | [Ivan's site]: http://appleii.ivanx.com/a2server/ 79 | -------------------------------------------------------------------------------- /files/dist/getexternal.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | if ! hash wget; then 5 | echo "wget is not installed. On a Mac, install it with MacPorts or Homebrew." 6 | fi 7 | 8 | echo "Downloading items..." 9 | 10 | mkdir -p files/external/source 11 | wget -O files/external/source/ciopfs-0.4.tar.gz http://www.brain-dump.org/projects/ciopfs/ciopfs-0.4.tar.gz 12 | wget -O files/external/source/macipgw.zip https://github.com/jasonking3/macipgw/archive/4f77c0933544767885c33c25545c48cc368a6dab.zip 13 | wget -O files/external/source/netatalk-2.4.10.tar.xz https://github.com/Netatalk/netatalk/releases/download/netatalk-2-4-10/netatalk-2.4.10.tar.xz 14 | wget -O files/external/source/nulib2-3.1.0a2.zip https://github.com/fadden/nulib2/archive/20fe7efb4d37fedf807416c16d74d51d893ea48a.zip 15 | wget -O files/external/source/unar-1.8.1.zip https://github.com/incbee/Unarchiver/archive/unar-1.8.1.zip 16 | 17 | mkdir -p files/external/appleii 18 | wget -O files/external/appleii/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 19 | wget -O files/external/appleii/p8.atalk.po http://apple2.guidero.us/lib/exe/fetch.php/projects/p8.atalk.po 20 | wget -O files/external/appleii/Asimov.shk http://www.ninjaforce.com/downloads/Asimov.shk 21 | wget -O files/external/appleii/MOUNTIT.SHK http://www.brutaldeluxe.fr/products/apple2gs/MOUNTIT.SHK 22 | wget -O files/external/appleii/TCPIP30b11.SHK http://www.apple2.org/marinetti/TCPIP30b11.SHK 23 | wget -O files/external/appleii/PPPX.1.3d4.SHK http://www.apple2.org/marinetti/PPPX.1.3d4.SHK 24 | wget -O files/external/appleii/dsk2file.shk http://dwheeler.com/6502/oneelkruns/dsk2file.zip 25 | wget -O files/external/appleii/gshk11.sea http://www.nulib.com/library/gshk11.sea 26 | wget -O files/external/appleii/shrinkit.sdk http://www.nulib.com/library/shrinkit.sdk 27 | wget -O files/external/appleii/spectrum_platinum_2mg.zip http://speccie.uk/speccie/downloads/spectrum_platinum.2mg.zip 28 | wget -O files/external/appleii/uthernet2ll.bxy http://speccie.uk/speccie/downloads/uthernet2ll.bxy 29 | wget -O files/external/appleii/uthernetll.bxy http://speccie.uk/speccie/downloads/uthernetll.bxy 30 | wget -O files/external/appleii/NetDisk10.shk https://github.com/sheumann/NetDisk/releases/download/v1.0/NetDisk10.shk 31 | wget -O files/external/appleii/AFPBridgeB1.shk https://github.com/sheumann/AFPBridge/releases/download/v1.0b1/AFPBridgeB1.shk 32 | wget -O files/external/appleii/smbfst10.shk https://github.com/sheumann/smbfst/releases/download/1.0/smbfst10.shk 33 | 34 | unset safeUrl samUrl snapUrl webberUrl networkerUrl checkfileUrl 35 | safeUrl=$(wget -qO- http://speccie.uk/software/safe2/ | grep -i 'safe2.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') 36 | samUrl=$(wget -qO- http://speccie.uk/software/sam2/ | grep -i 'sam2.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') 37 | snapUrl=$(wget -qO- http://speccie.uk/software/snap/ | grep -i 'snap.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') 38 | webberUrl=$(wget -qO- http://speccie.uk/software/webber/ | grep -i 'webber.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') 39 | networkerUrl=$(wget -qO- http://speccie.uk/software/networker2/ | grep -i 'netwrk.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') 40 | checkfileUrl=$(wget -qO- http://speccie.uk/software/check-file-permanent-initialisation-file/ | grep -i 'chkfile.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') 41 | wget -O files/external/appleii/safe2.bxy "$safeUrl" 42 | wget -O files/external/appleii/sam2.bxy "$samUrl" 43 | wget -O files/external/appleii/snap.bxy "$snapUrl" 44 | wget -O files/external/appleii/webber.bxy "$webberUrl" 45 | wget -O files/external/appleii/networker.bxy "$networkerUrl" 46 | wget -O files/external/appleii/checkfile.bxy "$checkfileUrl" 47 | 48 | mkdir -p files/appleii 49 | mkdir -p files/appleii/a2ws 50 | wget -O files/appleii/a2ws/A2GS.WS.HDV https://appleii.ivanx.com/a2server/files/appleii/a2ws/A2GS.WS.HDV 51 | wget -O files/appleii/MarinettiB1.SHK https://appleii.ivanx.com/a2server/files/appleii/MarinettiB1.SHK 52 | wget -O files/appleii/FARALLON.B1.PO https://appleii.ivanx.com/a2server/files/appleii/FARALLON.B1.PO 53 | wget -O files/appleii/A2CLOUD.HDV https://appleii.ivanx.com/a2server/files/appleii/A2CLOUD.HDV 54 | wget -O files/safe2-setup.tgz https://appleii.ivanx.com/a2server/files/safe2-setup.tgz 55 | wget -O files/snap-groups.tgz https://appleii.ivanx.com/a2server/files/snap-groups.tgz 56 | wget -O files/snap-setup.tgz https://appleii.ivanx.com/a2server/files/snap-setup.tgz 57 | 58 | for gsosInstall in {1..4}; do 59 | activeDisk=0 60 | mkdir -p files/external/appleii/gsos60${gsosInstall} 61 | 62 | diskNames=( Install System.Disk SystemTools1 SystemTools2 Fonts synthLAB ) 63 | if (( $gsosInstall == 1 )); then 64 | gsosURL="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_IIGS_System_6.0.1%2F" 65 | wget -O files/external/appleii/gsos601/Disk_7_of_7-Apple_II_Setup.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_IIGS_System_6.0.1%2FDisk_7_of_7-Apple_II_Setup.sea.bin" 66 | elif (( $gsosInstall == 2 )); then 67 | gsosURL="http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Software/Operating%20Systems/Apple%20IIGS%20System/Disk%20Images/" 68 | diskNames=( Install System.Disk SystemTools1 SystemTools2 SystemTools3 Fonts1 Fonts2 synthLAB ) 69 | diskWebNames=( Install System%20disk System%20tools%201 System%20tools%202 System%20tools%203 Fonts%201 Fonts%202 Synthlab ) 70 | elif (( $gsosInstall == 3 )); then 71 | gsosURL="http://mirrors.apple2.org.za/ftp.apple.asimov.net/images/gs/os/gsos/Apple_IIGS_System_6.0.3/" 72 | elif (( $gsosInstall == 4 )); then 73 | diskNames=( Install System.Disk SystemTools1 SystemTools2 SystemTools3 Fonts Fonts2 synthLAB ) 74 | gsosURL="http://mirrors.apple2.org.za/ftp.apple.asimov.net/images/gs/os/gsos/Apple_IIGS_System_6.0.4/PO%20Disk%20Images/" 75 | fi 76 | 77 | for diskname in ${diskNames[@]}; do 78 | outfile="files/external/appleii/gsos60${gsosInstall}/$diskname.po" 79 | (( activeDisk++ )) 80 | if (( $gsosInstall == 1 )); then 81 | wget -O files/external/appleii/gsos601/"Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${gsosURL}Disk_${activeDisk}_of_7-${diskname}.sea.bin" 82 | elif (( $gsosInstall == 2 )); then 83 | wget -O $outfile "$gsosURL/IIGS%20System%206.0.2%20-%20Disk%20${activeDisk}%20${diskWebNames[$activeDisk-1]}.po" 84 | elif (( $gsosInstall == 3 )); then 85 | wget -O $outfile "$gsosURL/$diskname.po" 86 | elif (( $gsosInstall == 4 )); then 87 | wget -O $outfile "$gsosURL/$diskname.po" 88 | fi 89 | done 90 | done 91 | -------------------------------------------------------------------------------- /files/macip-prefs.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NJRoadfan/a2server/2e6d35edc89c1d9a0ace9766d865cb74e01c64c3/files/macip-prefs.tgz -------------------------------------------------------------------------------- /files/macipgw-start.sh.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Start MacIPgw (TCP over AppleTalk) service 3 | #ps aux | grep -q "[m]acipgw" && sudo pkill macipgw || : 4 | atalkd_if=$(grep "^[^ # t]" /etc/netatalk/atalkd.conf | tail -1 | cut -d " " -f 1) 5 | sysctl -w net.ipv4.ip_forward=1 > /dev/null 6 | macipgw -n 8.8.8.8 192.168.151.0 255.255.255.0 7 | # Enable IP NAT forwarding 8 | nft flush ruleset 9 | nft 'add table ip filter' 10 | nft 'add chain ip filter INPUT { type filter hook input priority 0; policy accept; }' 11 | nft 'add chain ip filter FORWARD { type filter hook forward priority 0; policy accept; }' 12 | nft 'add chain ip filter OUTPUT { type filter hook output priority 0; policy accept; }' 13 | nft add rule ip filter FORWARD iifname "$atalkd_if" oifname "tun0" ct state related,established counter accept 14 | nft 'add table ip nat' 15 | nft 'add chain ip nat PREROUTING { type nat hook prerouting priority -100; policy accept; }' 16 | nft 'add chain ip nat INPUT { type nat hook input priority 100; policy accept; }' 17 | nft 'add chain ip nat OUTPUT { type nat hook output priority -100; policy accept; }' 18 | nft 'add chain ip nat POSTROUTING { type nat hook postrouting priority 100; policy accept; }' 19 | nft add rule ip nat POSTROUTING oifname "$atalkd_if" counter masquerade 20 | -------------------------------------------------------------------------------- /files/macipgw.service.txt: -------------------------------------------------------------------------------- 1 | # This is experimental service file. 2 | # See distrib/systemd/README 3 | # This file is part of Netatalk 2.221101. 4 | 5 | [Unit] 6 | Description=MacIP Gateway daemon 7 | After=network.target atalkd.service 8 | Requires=atalkd.service 9 | 10 | [Service] 11 | Type=forking 12 | GuessMainPID=no 13 | ExecStart=/usr/local/sbin/macipgw-start.sh 14 | Restart=always 15 | RestartSec=1 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | Also=atalkd.service 20 | -------------------------------------------------------------------------------- /files/netatalk-init.d-clean.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: netatalk 4 | # Required-Start: $remote_fs $syslog 5 | # Should-Start: avahi-daemon 6 | # Required-Stop: $remote_fs $syslog 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 1 9 | ### END INIT INFO 10 | # 11 | # netatalk Netatalk 2.2.4 initscript 12 | # Author: Thomas Kaiser 13 | 14 | set -e 15 | 16 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 17 | DESC="Netatalk" 18 | NAME=netatalk 19 | SCRIPTNAME=/etc/init.d/$NAME 20 | 21 | # Guard to prevent execution if netatalk was removed. 22 | test -x /usr/local/sbin/afpd || exit 0 23 | 24 | # Set defaults. Please change these options in /etc/default/netatalk 25 | ATALK_NAME=`/bin/hostname --short` 26 | ATALK_UNIX_CHARSET='LOCALE' 27 | ATALK_MAC_CHARSET='MAC_ROMAN' 28 | 29 | CNID_METAD_RUN=yes 30 | AFPD_RUN=yes 31 | AFPD_MAX_CLIENTS=50 32 | AFPD_UAMLIST="-U uams_dhx2.so" 33 | AFPD_GUEST=nobody 34 | CNID_CONFIG="-l log_note" 35 | 36 | ATALKD_RUN=no 37 | PAPD_RUN=no 38 | TIMELORD_RUN=no 39 | #A2BOOT_RUN=no 40 | ATALK_ZONE= 41 | ATALK_BGROUND=no 42 | 43 | # old /etc/default/netatalk expected hostname in $HOSTNAME by default 44 | HOSTNAME=`/bin/hostname` 45 | 46 | # Read in netatalk configuration. 47 | if [ -f /etc/default/netatalk ]; then 48 | . /etc/default/netatalk 49 | fi 50 | 51 | # Start Netatalk servers. 52 | atalk_startup() { 53 | if [ x"$ATALKD_RUN" = x"yes" ]; then 54 | 55 | # Try to load the AppleTalk kernel module if it was intended. 56 | if grep -q '^appletalk$' /etc/modules; then 57 | /sbin/modprobe appletalk || echo "[could not load appletalk module]" 58 | fi 59 | 60 | # Start atalkd server. 61 | /usr/local/sbin/atalkd 62 | 63 | # register workstation 64 | /usr/local/bin/nbprgstr -p 4 "$ATALK_NAME:Workstation$ATALK_ZONE" 65 | /usr/local/bin/nbprgstr -p 4 "$ATALK_NAME:netatalk$ATALK_ZONE" 66 | 67 | echo -n " atalkd" 68 | fi 69 | 70 | # prepare startup of file services 71 | if [ "x$CNID_METAD_RUN" = "xyes" -a -x /usr/local/sbin/cnid_metad ] ; then 72 | echo -n " cnid_metad" 73 | /usr/local/sbin/cnid_metad $CNID_CONFIG 74 | fi 75 | 76 | if [ x"$AFPD_RUN" = x"yes" ]; then 77 | /usr/local/sbin/afpd $AFPD_UAMLIST -g $AFPD_GUEST -c $AFPD_MAX_CLIENTS \ 78 | -n "$ATALK_NAME$ATALK_ZONE" 79 | echo -n " afpd" 80 | fi 81 | 82 | if [ "x$ATALKD_RUN" = "xyes" ]; then 83 | if [ "x$PAPD_RUN" = "xyes" ]; then 84 | /usr/local/sbin/papd 85 | echo -n " papd" 86 | fi 87 | 88 | if [ x"$TIMELORD_RUN" = x"yes" ]; then 89 | /usr/local/sbin/timelord 90 | echo -n " timelord" 91 | fi 92 | fi 93 | } 94 | 95 | case "$1" in 96 | start) 97 | if [ "x$ATALK_BGROUND" = "xyes" -a "x$ATALKD_RUN" = "xyes" ]; then 98 | echo "Starting Netatalk services in the background." 99 | atalk_startup >/dev/null & 100 | else 101 | echo -n "Starting Netatalk services (this will take a while): " 102 | atalk_startup 103 | echo "." 104 | fi 105 | ;; 106 | 107 | stop) 108 | echo -n "Stopping Netatalk Daemons:" 109 | echo -n " afpd" 110 | start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/afpd 111 | 112 | echo -n " cnid_metad" 113 | start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/cnid_metad 114 | 115 | if test -x /usr/local/sbin/papd; then 116 | echo -n " papd" 117 | start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/papd 118 | fi 119 | 120 | if test -x /usr/local/sbin/timelord; then 121 | echo -n " timelord" 122 | start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/timelord 123 | fi 124 | 125 | if test -x /usr/local/sbin/atalkd; then 126 | echo -n " atalkd" 127 | start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/atalkd 128 | fi 129 | 130 | echo "." 131 | ;; 132 | 133 | restart) 134 | $0 force-reload 135 | ;; 136 | 137 | force-reload) 138 | echo -n "Restarting Netatalk Daemons (this will take a while)" 139 | $0 stop 140 | echo -n "." 141 | sleep 2 142 | echo -n "." 143 | if $0 start; then 144 | echo "done." 145 | fi 146 | ;; 147 | 148 | *) 149 | echo "Usage: $0 {start|stop|restart|force-reload}" >&2 150 | exit 1 151 | ;; 152 | esac 153 | -------------------------------------------------------------------------------- /files/netatalkpatches.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NJRoadfan/a2server/2e6d35edc89c1d9a0ace9766d865cb74e01c64c3/files/netatalkpatches.tar.gz -------------------------------------------------------------------------------- /files/tash0.txt: -------------------------------------------------------------------------------- 1 | #This file should be in /etc/network/interfaces.d/ 2 | #Creates a persistent TAP interface named "tash0" to link TashRouter and atalkd. 3 | 4 | auto tash0 5 | iface tash0 inet manual 6 | pre-up tunctl -t tash0 -u root 7 | up ip link set dev tash0 up 8 | down ip link set dev tash0 down 9 | -------------------------------------------------------------------------------- /files/tashrouter.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import time 3 | import signal 4 | import sys 5 | 6 | import tashrouter.netlog 7 | from tashrouter.port.ethertalk.tap import TapPort 8 | from tashrouter.port.localtalk.ltoudp import LtoudpPort 9 | #from tashrouter.port.localtalk.tashtalk import TashTalkPort 10 | from tashrouter.router.router import Router 11 | 12 | def sigterm_handler(_signo, _stack_frame): 13 | # Raises SystemExit(0): 14 | sys.exit(0) 15 | 16 | logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') 17 | #tashrouter.netlog.set_log_str_func(logging.debug) # comment this line for speed and reduced spam 18 | 19 | router = Router('router', ports=( 20 | LtoudpPort(seed_network=5, seed_zone_name=b'A2SERVER'), 21 | #TashTalkPort(serial_port='/dev/ttyAMA0', seed_network=6, seed_zone_name=b'A2SERVER'), 22 | TapPort(tap_name='tash0', hw_addr=b'\xAA\xBB\xCC\xDD\x11\x22', seed_network_min=6502, seed_network_max=6502, seed_zone_names=[b'A2SERVER']), 23 | )) 24 | print('router away!') 25 | router.start() 26 | signal.signal(signal.SIGTERM, sigterm_handler) 27 | 28 | try: 29 | while True: time.sleep(1) 30 | except (KeyboardInterrupt, SystemExit): 31 | router.stop() 32 | -------------------------------------------------------------------------------- /files/tashrouter.service.txt: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=TashRouter AppleTalk Router 3 | Documentation=https://github.com/lampmerchant/tashrouter 4 | After=network-online.target 5 | Wants=network-online.target 6 | 7 | [Service] 8 | User=root 9 | Type=simple 10 | ExecStart=/usr/bin/python3 /usr/local/sbin/tashrouter.py 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /fix/fix.txt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo 4 | echo "A2SERVER fix: This utility will make a Raspberry Pi SD card boot if it" 5 | echo "kernel panics (crashes) on startup after updating its operating system" 6 | echo "while A2SERVER is installed." 7 | echo 8 | echo -n "Continue? " 9 | read 10 | doFix= 11 | if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then 12 | while true; do 13 | echo 14 | echo "If attached, remove the Raspberry Pi's SD card from this computer." 15 | echo -n "Press return to continue..."; read; echo 16 | 17 | ls -1 /dev/sd? > /tmp/sd1 2> /dev/null 18 | 19 | echo "Insert the Raspberry Pi's SD card into this computer, using a USB" 20 | echo "reader if you don't have an SD slot. If this is a virtual machine," 21 | echo "make sure you select the reader or SD slot from its USB menu." 22 | echo -n "Press return to continue..."; read; echo 23 | 24 | ls -1 /dev/sd? > /tmp/sd2 2> /dev/null 25 | 26 | # if exactly one drive has been inserted, exit loop 27 | if { ! diff /tmp/sd1 /tmp/sd2 &> /dev/null; }; then 28 | # files are different, get dev name 29 | if [[ $(wc -c /tmp/sd1 | cut -f 1 -d ' ') -eq 0 ]]; then 30 | if [[ $(wc -l /tmp/sd2 | cut -f 1 -d ' ') -eq 1 ]]; then 31 | devName=$(cat /tmp/sd2) 32 | break 33 | else 34 | echo "More than one volume seems to have appeared. Trying again..." 35 | echo 36 | fi 37 | else 38 | devName=$(grep -v "$(cat /tmp/sd1)" /tmp/sd2) 39 | if [[ $(wc -l <<< $devName) -eq 1 ]]; then 40 | break 41 | else 42 | echo "More than one volume seems to have appeared. Trying again..." 43 | echo 44 | fi 45 | fi 46 | else 47 | echo "No SD card found. Trying again..." 48 | echo 49 | fi 50 | 51 | done 52 | 53 | mkdir -p /tmp/sd 54 | sudo mount ${devName}6 /tmp/sd 55 | 56 | 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) 57 | doFix= 58 | if [[ $raspbianDate -lt 1403204265 ]]; then 59 | echo "This doesn't appear to be a version of Raspbian that requires fixing." 60 | echo -n "Are you sure you want to continue? " 61 | read 62 | if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then 63 | doFix=1 64 | fi 65 | else 66 | doFix=1 67 | fi 68 | 69 | if [[ $doFix ]]; then 70 | while read kernelRelease; do 71 | kernelReplaced= 72 | kernelMajorRelease=$(cut -d '.' -f 1 <<< $kernelRelease) 73 | kernelMinorRelease=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') 74 | kernelPatchRelease=$(cut -d '.' -f 3- <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') 75 | # if kernel 3.12 below 3.12.25+, delete defective AppleTalk kernel 76 | if [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -eq 12 && $kernelPatchRelease -lt 25 ]]; then 77 | if [[ -f /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then 78 | if [[ $(sha1sum /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then 79 | echo "Removing defective AppleTalk module from kernel $kernelRelease..." 80 | sudo rm -rf /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null 81 | wget -qO /tmp/appletalk.ko.gz ${A2SERVER_SCRIPT_URL}files/appletalk-$kernelRelease.ko.gz 82 | if [[ $? -eq 0 ]]; then 83 | # if we found a prebuilt one on a2server site, so install it 84 | gunzip -f /tmp/appletalk.ko.gz 85 | sudo mkdir -p /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk 86 | sudo mv /tmp/appletalk.ko /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk 87 | echo "Installed fixed AppleTalk module for kernel $kernelRelease." 88 | kernelReplaced=1 89 | fi 90 | fi 91 | fi 92 | fi 93 | done <<< "$(ls -1 /tmp/sd/lib/modules | sort -V)" 94 | sudo umount /tmp/sd 95 | 96 | echo kern:$kernelReplaced 97 | if [[ $kernelReplaced ]]; then 98 | echo 99 | echo "All set. Remove your SD card, put it back in your Pi, and boot it." 100 | echo 101 | echo "You should be able to connect from your Apple II, but if you can't," 102 | echo "log in to your Pi and type 'a2server-setup' to complete the fix." 103 | else 104 | echo 105 | echo "Okey doke. Half done. Remove your SD card, and put it back in your Pi." 106 | echo "After it boots, log in and type 'a2server-setup' to complete the fix." 107 | fi 108 | echo "See the A2SERVER web site at http://ivanx.com/a2server for more help." 109 | echo "(You can type 'sudo shutdown -h now' if you're done on this machine.)" 110 | echo 111 | fi 112 | fi 113 | 114 | rm fix &> /dev/null 115 | -------------------------------------------------------------------------------- /scripts/a2server-1-storage.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # --- Setting up the share volume 5 | 6 | # 1.3.0: move /media/A2SHARED (pre-1.3.0) to /srv/A2SERVER 7 | if [[ -d /media/A2SHARED ]]; then 8 | echo "A2SERVER: Moving /media/A2SHARED to /srv/A2SERVER..." 9 | sudo /etc/init.d/netatalk stop &> /dev/null 10 | sudo /etc/init.d/samba stop &> /dev/null 11 | [[ ! -d /srv ]] && sudo mkdir -p /srv 12 | sudo mv /media/A2SHARED /srv/A2SERVER 13 | sudo sed -i 's|/media/A2SHARED|/srv/A2SERVER|g' /usr/local/etc/netatalk/AppleVolumes.default 14 | [[ -f /etc/samba/smbd.conf ]] && sudo sed -i 's|/media/A2SHARED|/srv/A2SERVER|g' /etc/samba/smbd.conf 15 | 16 | fi 17 | 18 | # skip if we're already set up 19 | if [[ -d /srv/A2SERVER ]]; then 20 | 21 | echo "A2SERVER: Shared volume is already prepared for use." 22 | 23 | else 24 | 25 | echo "A2SERVER: Preparing the shared files volume..." 26 | 27 | sudo mkdir -p /srv/A2SERVER 28 | 29 | sudo chown $USER:$USER /srv/A2SERVER 30 | 31 | fi 32 | -------------------------------------------------------------------------------- /scripts/a2server-2-tools.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # download and install a2server tools: 5 | # mkatinit, mkvolinfo, afptype, afpsync, aliases, nulib2 6 | 7 | # Ensure URL we'll use ends in a / 8 | case "$A2SERVER_SCRIPT_URL" in 9 | */) scriptURL="$A2SERVER_SCRIPT_URL" ;; 10 | *) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/NJRoadfan/a2server/currentdev}/" ;; 11 | esac 12 | case "$A2SERVER_BINARY_URL" in 13 | */) binaryURL="$A2SERVER_BINARY_URL" ;; 14 | *) binaryURL="${A2SERVER_BINARY_URL:-https://appleii.ivanx.com/a2server/files}/" ;; 15 | esac 16 | useExternalURL=1 17 | [[ $A2SERVER_NO_EXTERNAL ]] && useExternalURL= 18 | 19 | debianVersion=$(cat /etc/debian_version 2> /dev/null) 20 | isRpi= 21 | arch= 22 | if [[ -f /usr/bin/raspi-config ]]; then 23 | isRpi=1 24 | arch='unknown' 25 | elif lsb_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ $(cut -d . -f 1 <<< $debianVersion) -ge "7" ]]; then 26 | uname_m="$(uname -m)" 27 | if [[ $uname_m == "i686" ]]; then 28 | arch='debian_x86' 29 | elif [[ $uname_m == "x86_64" ]]; then 30 | arch='debian_x64' 31 | fi 32 | fi 33 | 34 | debianName= 35 | if [[ $debianVersion ]]; then 36 | debianMajor=$(cut -d . -f 1 <<< $debianVersion) 37 | if [[ $debianMajor == "12" ]]; then 38 | debianName="bookworm" 39 | elif [[ $debianMajor == "11" ]]; then 40 | debianName="bullseye" 41 | elif [[ $debianMajor == "10" ]]; then 42 | debianName="buster" 43 | elif [[ $debianMajor == "9" ]]; then 44 | debianName="stretch" 45 | elif [[ $debianMajor == "8" ]]; then 46 | debianName="jessie" 47 | elif [[ $debianMajor == "7" ]]; then 48 | debianName="wheezy" 49 | else 50 | debianName="unknown" 51 | fi 52 | fi 53 | 54 | echo "A2SERVER: Installing A2SERVER tools..." 55 | 56 | # delete older nulib2 which doesn't correctly handle zero-length forks in GSHK-created archives 57 | if hash nulib2 &> /dev/null; then 58 | nulib2version=$(nulib2 | sed -n 2p | sed 's|^.*v\([0-9]\)\.\([0-9]\)\.\([0-9]\).*$|\1\2\3|' 2> /dev/null) 59 | if (( $nulib2version < 310 )); then 60 | sudo apt-get -y purge nulib2 &> /dev/null 61 | sudo rm $(command -v nulib2) &> /dev/null 62 | fi 63 | fi 64 | 65 | if ! hash nulib2 &> /dev/null; then 66 | 67 | echo "A2SERVER: Installing nulib2..." 68 | 69 | cd /tmp 70 | if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then 71 | { wget -qO- "${binaryURL}precompiled/nulib2-3.1.0a2-${arch}.tgz" | sudo tar Pzx; } &> /dev/null 72 | fi 73 | 74 | if ! hash nulib2 &> /dev/null; then 75 | if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then 76 | # prepare for installing packages 77 | sudo apt-get -y update 78 | touch /tmp/a2server-packageReposUpdated 79 | fi 80 | 81 | sudo apt-get -y install nulib2 82 | sudo apt-get clean 83 | 84 | # If all else fails, compile from source. 85 | if ! hash nulib2 &> /dev/null; then 86 | # Dependencies: build-dep for nulib 87 | sudo apt-get -y install build-essential zlib1g-dev 88 | sudo apt-get -y clean 89 | 90 | cd /tmp 91 | rm -rf /tmp/nulib2 &> /dev/null 92 | mkdir /tmp/nulib2 93 | cd /tmp/nulib2 94 | if [[ $useExternalURL ]]; then 95 | wget -q -O nulib2-3.1.0a2.zip "https://github.com/fadden/nulib2/archive/20fe7efb4d37fedf807416c16d74d51d893ea48a.zip" 96 | unzip nulib2-3.1.0a2.zip 2> /dev/null 97 | rm nulib2-3.1.0a2.zip &> /dev/null 98 | fi 99 | if [ ! -d nulib2* ]; then 100 | wget -q -O nulib2-3.1.0a2.zip "${binaryURL}external/source/nulib2-3.1.0a2.zip" 101 | unzip nulib2-3.1.0a2.zip 2> /dev/null 102 | rm nulib2-3.1.0a2.zip &> /dev/null 103 | fi 104 | cd nulib2* 105 | cd nufxlib 106 | ./configure 107 | if [[ -f /tmp/a2server-multiThreadedCompilation ]]; then 108 | echo "Compiling nufxlib with $(nproc) threads..." 109 | make -j "$(nproc)" 110 | else 111 | make 112 | fi 113 | sudo make install 114 | cd ../nulib2 115 | ./configure 116 | if [[ -f /tmp/a2server-multiThreadedCompilation ]]; then 117 | echo "Compiling nulib2 with $(nproc) threads..." 118 | make -j "$(nproc)" 119 | else 120 | make 121 | fi 122 | sudo make install 123 | cd 124 | rm -rf /tmp/nulib2 125 | fi 126 | fi 127 | else 128 | echo "A2SERVER: Nulib2 has already been installed." 129 | fi 130 | 131 | # download and install The Unarchiver, for expanding Apple disk images 132 | # http://wakaba.c3.cx/s/apps/unarchiver.html 133 | 134 | if ! hash unar &> /dev/null; then 135 | 136 | echo "A2SERVER: Installing The Unarchiver..." 137 | 138 | if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then 139 | # prepare for installing packages 140 | sudo apt-get -y update 141 | touch /tmp/a2server-packageReposUpdated 142 | fi 143 | 144 | # jessie and later: Just use the unar package 145 | 146 | sudo apt-get -y install unar 147 | sudo apt-get clean 148 | 149 | if ! hash unar &> /dev/null; then 150 | if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then 151 | # Dependencies: for unar 152 | sudo apt-get -y install libgnustep-base1.22 153 | sudo apt-get clean 154 | { wget -qO- "${binaryURL}precompiled/unar-${arch}_${debianName}.tgz" | sudo tar Pzx; } &> /dev/null 155 | fi 156 | 157 | # If all else fails, compile from source. 158 | if ! hash unar &> /dev/null; then 159 | 160 | # Dependencies: build-deps for unar 161 | sudo apt-get -y install build-essential libgnustep-base-dev libz-dev libbz2-dev libssl-dev libicu-dev unzip 162 | sudo apt-get clean 163 | 164 | rm -rf /tmp/unar &> /dev/null 165 | mkdir /tmp/unar 166 | cd /tmp/unar 167 | if [[ $useExternalURL ]]; then 168 | wget -O unar-1.8.1.zip https://github.com/incbee/Unarchiver/archive/unar-1.8.1.zip 169 | unzip -o unar-1.8.1.zip &> /dev/null 170 | fi 171 | if [ ! -d *Unarchiver*/XADMaster ]; then # need single bracket for glob 172 | wget -O unar-1.8.1.zip ${binaryURL}external/source/unar-1.8.1.zip 173 | unzip -o unar-1.8.1.zip &> /dev/null 174 | fi 175 | cd *Unarchiver*/XADMaster 176 | make -f Makefile.linux 177 | sudo mv lsar unar /usr/local/bin 178 | cd ../Extra 179 | sudo mv lsar.1 unar.1 /usr/local/man/man1 180 | cd 181 | rm -rf /tmp/unar 182 | fi 183 | sudo mandb &> /dev/null 184 | fi 185 | else 186 | echo "A2SERVER: The Unarchiver has already been installed." 187 | fi 188 | 189 | if ! hash unzip &> /dev/null; then 190 | echo "A2SERVER: Installing unzip..." 191 | if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then 192 | # prepare for installing packages 193 | sudo apt-get -y update 194 | touch /tmp/a2server-packageReposUpdated 195 | fi 196 | 197 | # Dependencies: unzip 198 | sudo apt-get -y install unzip 199 | sudo apt-get clean 200 | else 201 | echo "A2SERVER: unzip has already been installed." 202 | fi 203 | 204 | sudo wget -q -O /usr/local/bin/afpsync "${scriptURL}scripts/tools/afpsync.txt" 205 | sudo chmod ugo+x /usr/local/bin/afpsync 206 | sudo wget -q -O /usr/local/bin/afptype "${scriptURL}scripts/tools/afptype.txt" 207 | sudo chmod ugo+x /usr/local/bin/afptype 208 | sudo wget -q -O /usr/local/bin/mkatinit "${scriptURL}scripts/tools/mkatinit.txt" 209 | sudo chmod ugo+x /usr/local/bin/mkatinit 210 | sudo wget -q -O /usr/local/bin/mkvolinfo "${scriptURL}scripts/tools/mkvolinfo.txt" 211 | sudo chmod ugo+x /usr/local/bin/mkvolinfo 212 | sudo wget -q -O /usr/local/bin/cppo "${scriptURL}scripts/tools/cppo.txt" 213 | sudo chmod ugo+x /usr/local/bin/cppo 214 | sudo wget -q -O /usr/local/etc/a2server-help.txt "${scriptURL}scripts/tools/a2server-help.txt" 215 | sudo wget -q -O /usr/local/etc/a2server-aliases "${scriptURL}scripts/tools/a2server-aliases.txt" 216 | sudo wget -q -O /usr/local/etc/a2serverrc "${scriptURL}scripts/tools/a2serverrc.txt" 217 | 218 | # fix aliases for different ethernet interface names on rpi 219 | if [ $isRpi ]; then 220 | sudo sed -i 's/enp0s3/eth0/' /usr/local/etc/a2server-aliases 221 | fi 222 | 223 | # 1.3.0: a2serverrc is now called from /etc/bash.bashrc, 224 | # which in turn calls a2server-aliases 225 | grep 'a2server-aliases' /etc/bash.bashrc > /dev/null && \ 226 | sudo sed -i 's/a2server-aliases/a2serverrc/' /etc/bash.bashrc 227 | grep 'a2serverrc' /etc/bash.bashrc > /dev/null || \ 228 | echo "source /usr/local/etc/a2serverrc" | sudo tee -a /etc/bash.bashrc > /dev/null 229 | 230 | motd="/etc/motd" 231 | if [[ ! $(grep A2SERVER $motd) ]]; then 232 | echo | sudo tee -a $motd > /dev/null 233 | echo "Type 'system-shutdown' to turn off A2SERVER." | sudo tee -a $motd > /dev/null 234 | echo "Type 'a2server-setup' to configure network boot." | sudo tee -a $motd > /dev/null 235 | echo "Type 'a2server-help' for a list of other commands." | sudo tee -a $motd > /dev/null 236 | echo | sudo tee -a $motd > /dev/null 237 | fi 238 | -------------------------------------------------------------------------------- /scripts/a2server-3-sharing.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # A2SERVER -- a virtual machine for sharing files to Apple II clients 5 | # by Ivan X, ivan@ivanx.com 6 | 7 | # Installs Netatalk 2.x for debian/raspbian 8 | 9 | # Thanks to Steven Hirsch, Geoff Body, Peter Wong, Tony Diaz, and others 10 | # at comp.sys.apple2 for the work they've done and insight they've 11 | # offered which made it possible to put this together. 12 | 13 | 14 | 15 | # --- Installing netatalk 16 | 17 | # Ensure URL we'll use ends in a / 18 | case "$A2SERVER_SCRIPT_URL" in 19 | */) scriptURL="$A2SERVER_SCRIPT_URL" ;; 20 | *) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/NJRoadfan/a2server/currentdev}/" ;; 21 | esac 22 | case "$A2SERVER_BINARY_URL" in 23 | */) binaryURL="$A2SERVER_BINARY_URL" ;; 24 | *) binaryURL="${A2SERVER_BINARY_URL:-https://appleii.ivanx.com/a2server/files}/" ;; 25 | esac 26 | useExternalURL=1 27 | [[ $A2SERVER_NO_EXTERNAL ]] && useExternalURL= 28 | 29 | debianVersion=$(cat /etc/debian_version 2> /dev/null) 30 | isRpi= 31 | arch= 32 | if [[ -f /usr/bin/raspi-config ]]; then 33 | isRpi=1 34 | arch='unknown' 35 | elif lsb_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ $(cut -d . -f 1 <<< $debianVersion) -ge "11" ]]; then 36 | uname_m="$(uname -m)" 37 | if [[ $uname_m == "i686" ]]; then 38 | arch='debian_x86' 39 | elif [[ $uname_m == "x86_64" ]]; then 40 | arch='debian_x64' 41 | fi 42 | fi 43 | 44 | debianName= 45 | if [[ $debianVersion ]]; then 46 | debianMajor=$(cut -d . -f 1 <<< $debianVersion) 47 | if [[ $debianMajor == "12" ]]; then 48 | debianName="bookworm" 49 | elif [[ $debianMajor == "11" ]]; then 50 | debianName="bullseye" 51 | else 52 | debianName="unknown" 53 | fi 54 | fi 55 | 56 | # enable SSH (disabled by default in Raspbian from late 2016 onward) 57 | if [[ $isRpi && $debianMajor -ge 8 ]] && ! ps aux | grep -q '[s]shd'; then 58 | echo "A2SERVER: Enabling ssh access..." 59 | sudo systemctl enable ssh &> /dev/null && sudo systemctl start ssh &> /dev/null 60 | else 61 | echo "A2SERVER: ssh access is already enabled." 62 | fi 63 | 64 | # skip this if already done 65 | if [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) >= 199 )); then 66 | 67 | echo "A2SERVER: Netatalk is already installed." 68 | 69 | else 70 | 71 | echo "A2SERVER: Installing Netatalk (this will take a while)..." 72 | 73 | # stop Netatalk and samba if running (during upgrade) 74 | if [[ $(ps --no-headers -C afpd) ]]; then 75 | sudo /etc/init.d/netatalk stop &> /dev/null 76 | sudo /etc/init.d/samba stop &> /dev/null 77 | sudo systemctl stop atalkd afpd papd timelord a2boot macipgw &> /dev/null 78 | sudo systemctl stop smbd nmbd &> /dev/null 79 | fi 80 | 81 | if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then 82 | # prepare for installing packages 83 | sudo apt-get -y update 84 | touch /tmp/a2server-packageReposUpdated 85 | fi 86 | 87 | # not being used as of 1.2.9, but it's available if full URL to .deb package is supplied 88 | getOldPackage () { 89 | for url in $@; do 90 | pkgFile=${url##*/} 91 | pkgName=${pkgFile%%_*} 92 | if ! dpkg -l $pkgName 2> /dev/null | grep -q '^ii'; then 93 | if [[ $useExternalURL ]]; then 94 | wget -qO "/tmp/${url##*/}" "$url" 95 | fi 96 | if [[ $? -ne 0 || ! -f "/tmp/${url##*/}" ]]; then 97 | wget -qO "/tmp/${url##*/}" "${binaryURL}external/deb/${url##*/}" 98 | fi 99 | sudo dpkg -i "/tmp/${url##*/}" 100 | sudo apt-get clean 101 | rm "/tmp/${url##*/}" 102 | fi 103 | done 104 | } 105 | 106 | # Dependencies: build-deps for netatalk 2.x 107 | sudo apt-get install --no-install-recommends --assume-yes build-essential cups cups-browsed avahi-daemon libnss-mdns libcups2-dev libssl-dev libavahi-client-dev libdb5.3-dev libgcrypt20-dev libpam0g-dev ninja-build uml-utilities docbook-xsl xsltproc 108 | 109 | sudo apt-get clean 110 | 111 | # bullseye needs to get meson from pip 112 | if [[ $debianName == "bullseye" ]]; then 113 | sudo apt-get install --assume-yes python3-pip 114 | sudo apt-get clean 115 | sudo pip install meson 116 | else 117 | sudo apt-get install --assume-yes meson 118 | sudo apt-get clean 119 | fi 120 | 121 | # get Netatalk 122 | rm -rf /tmp/netatalk &> /dev/null 123 | mkdir /tmp/netatalk 124 | cd /tmp/netatalk 125 | 126 | if [[ $useExternalURL ]]; then 127 | wget -qO netatalk-2.4.10.tar.xz "https://github.com/Netatalk/netatalk/releases/download/netatalk-2-4-10/netatalk-2.4.10.tar.xz" 128 | tar xf netatalk-2.4.10.tar.xz &> /dev/null 129 | fi 130 | 131 | if [[ ! -d netatalk-2.4.10 ]]; then 132 | wget -O netatalk-2.4.10.tar.xz "${binaryURL}external/source/netatalk-2.4.10.tar.xz" 133 | tar xf netatalk-2.4.10.tar.xz &> /dev/null 134 | fi 135 | 136 | cd netatalk-2.4.10 137 | 138 | # prepare to build Netatalk 139 | #./configure --enable-systemd --enable-cups --disable-quota 140 | meson setup build -Dwith-embedded-ssl=true -Dwith-quota=false -Dwith-init-style=debian-systemd -Dwith-pkgconfdir-path=/usr/local/etc/netatalk 141 | 142 | # uninstall Netatalk if already installed 143 | #[[ -f /usr/local/sbin/afpd ]] && sudo make uninstall 144 | 145 | # compile and install Netatalk 146 | if [[ -f /tmp/a2server-multiThreadedCompilation ]]; then 147 | echo "Compiling Netatalk with $(nproc) threads..." 148 | #make all -j "$(nproc)" 149 | meson compile -C build 150 | else 151 | #make all 152 | meson compile -C build 153 | fi 154 | # uninstall Netatalk if already installed 155 | [[ -f /usr/local/sbin/afpd ]] && sudo ninja -C build uninstall 156 | 157 | #sudo make install 158 | sudo meson install -C build 159 | 160 | # to remove the Netatalk source code (optional), type: 161 | cd 162 | rm -rf /tmp/netatalk 163 | fi 164 | 165 | # --- Install MacIPgw 166 | if ! hash macipgw &> /dev/null; then 167 | echo "A2SERVER: Installing TCP over AppleTalk (MacIP)..." 168 | 169 | if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then 170 | { wget -qO- "${binaryURL}precompiled/macipgw-${arch}.tgz" | sudo tar Pzx; } 2> /dev/null 171 | fi 172 | 173 | if ! hash macipgw &> /dev/null; then 174 | wd="$PWD" 175 | sudo apt-get -y install build-essential 176 | rm -rf /tmp/macipgw &> /dev/null 177 | mkdir /tmp/macipgw 178 | cd /tmp/macipgw 179 | if [[ $useExternalURL ]]; then 180 | wget -qO macipgw.zip "https://github.com/jasonking3/macipgw/archive/4f77c0933544767885c33c25545c48cc368a6dab.zip" 181 | unzip macipgw.zip 2> /dev/null 182 | rm macipgw.zip &> /dev/null 183 | fi 184 | if [ ! -d macipgw* ]; then 185 | wget -qO macipgw.zip "${binaryURL}external/source/macipgw.zip" 186 | unzip macipgw.zip 2> /dev/null 187 | rm macipgw.zip &> /dev/null 188 | fi 189 | cd macipgw* 190 | make 191 | sudo make install 192 | cd "$wd" 193 | rm -rf /tmp/macipgw 194 | fi 195 | #copy over files required to setup macipgw on boot 196 | sudo wget -q -O /usr/lib/systemd/system/macipgw.service "${scriptURL}files/macipgw.service.txt" 197 | sudo wget -q -O /usr/local/sbin/macipgw-start.sh "${scriptURL}files/macipgw-start.sh.txt" 198 | sudo chmod ugo+x /usr/local/sbin/macipgw-start.sh 199 | else 200 | echo "A2SERVER: TCP over AppleTalk (MacIP) has already been installed." 201 | fi 202 | 203 | # --- Configuring Netatalk 204 | 205 | echo "A2SERVER: Configuring Netatalk..." 206 | 207 | # enable netatalk services on startup 208 | sudo systemctl enable atalkd afpd papd a2boot timelord macipgw 209 | 210 | # allow Guest users to be able to network boot 211 | # sudo sed -i "s/#AFPD_GUEST=nobody/AFPD_GUEST=$USER/" /etc/netatalk/netatalk.conf 212 | # (For a Guest user with different permissions than the compile-time user, create a 213 | # Linux user, and then specify that user for AFPD_GUEST instead.) 214 | 215 | # create a symbolic link to the startup configuration file in netatalk configuration folder 216 | #[[ -L /usr/local/etc/netatalk/netatalk.conf ]] \ 217 | #|| sudo ln -s /etc/default/netatalk /usr/local/etc/netatalk/netatalk.conf 218 | 219 | # create a symbolic link to the netatalk configuration folder in /etc 220 | [[ -L /etc/netatalk ]] || sudo ln -s /usr/local/etc/netatalk /etc/netatalk 221 | 222 | if [[ ! $(grep '^- -ddp.*uams_randnum.so' /usr/local/etc/netatalk/afpd.conf) ]]; then 223 | # set up to allow Guest, Cleartext, RandNum, DHX, and DHX2 login 224 | # disable DHX (DHCAST128) on Raspberry Pi, which refuses uams if the config string is too long 225 | [[ -f /usr/bin/raspi-config ]] && dhx="" || dhx="uams_dhx.so," 226 | echo -n -e \ 227 | "- -ddp -tcp -uamlist uams_guest.so,uams_clrtxt.so,uams_randnum.so" \ 228 | | sudo tee -a /usr/local/etc/netatalk/afpd.conf > /dev/null 229 | echo -e ",${dhx}uams_dhx2.so -guestname \"user1\"" \ 230 | | sudo tee -a /usr/local/etc/netatalk/afpd.conf > /dev/null 231 | fi 232 | 233 | # replace home folder share and end of file mark with share placeholders 234 | sudo sed -i 's/^~/#share1\n\n#share2/' \ 235 | /usr/local/etc/netatalk/AppleVolumes.default 236 | 237 | # disable home folder "name" in later netatalk builds 238 | sudo sed -i $'s/"$u\'s Home Directory"//g' \ 239 | /usr/local/etc/netatalk/AppleVolumes.default 240 | 241 | # disable default volume options for Mac OS X clients 242 | sudo sed -i 's/^:DEFAULT/#:DEFAULT/' \ 243 | /usr/local/etc/netatalk/AppleVolumes.default 244 | 245 | echo "A2SERVER: Configuring TashRouter..." 246 | 247 | sudo systemctl stop tashrouter &> /dev/null 248 | mkdir /tmp/tashrouter 249 | cd /tmp/tashrouter 250 | wget -qO tashrouter.zip "https://github.com/lampmerchant/tashrouter/archive/refs/heads/main.zip" 251 | unzip tashrouter.zip &> /dev/null 252 | cd tashrouter-main 253 | sudo cp -r tashrouter /usr/local/sbin 254 | sudo wget -q -O /usr/lib/systemd/system/tashrouter.service "${scriptURL}files/tashrouter.service.txt" 255 | sudo wget -q -O /usr/local/sbin/tashrouter.py "${scriptURL}files/tashrouter.py" 256 | 257 | # create tap interface to link netatalk and tashrouter 258 | if [[ ! $(ip a | grep 'tash0') ]]; then 259 | sudo ip tuntap add mode tap tash0 260 | sudo ip link set dev tash0 up 261 | fi 262 | # make sure it comes up after reboot 263 | sudo wget -q -O /etc/network/interfaces.d/tash0 "${scriptURL}files/tash0.txt" 264 | sudo systemctl enable tashrouter 265 | cd /tmp/ 266 | rm -rf tashrouter 267 | 268 | # if [[ ! $(grep ^eth0 /usr/local/etc/netatalk/atalkd.conf) && ! $(grep ^wlan0 /usr/local/etc/netatalk/atalkd.conf) ]]; then 269 | if [[ $(tac /usr/local/etc/netatalk/atalkd.conf | sed '/./,$!d' | head -1 | cut -c 1) == "#" ]]; then 270 | # enable tap interface for tashrouter 271 | echo -e 'tash0 -seed -phase 2 -net 6502 -addr 6502.16 -zone "A2SERVER"' | sudo tee -a /usr/local/etc/netatalk/atalkd.conf > /dev/null 272 | # enable netatalk on the default network interface 273 | if [ $isRpi ]; then 274 | echo -e 'eth0 -seed -phase 2 -net 1 -zone "A2SERVER"' | sudo tee -a /usr/local/etc/netatalk/atalkd.conf > /dev/null 275 | else 276 | echo -e 'enp0s3 -seed -phase 2 -net 1 -zone "A2SERVER"' | sudo tee -a /usr/local/etc/netatalk/atalkd.conf > /dev/null 277 | fi 278 | fi 279 | 280 | if [[ $isRpi ]];then 281 | # find config.txt 282 | if [ -e /boot/firmware/config.txt ] ; then 283 | FIRMWARE=/firmware 284 | else 285 | FIRMWARE= 286 | fi 287 | if [ -e /proc/device-tree/chosen/os_prefix ]; then 288 | PREFIX="$(tr -d '\0' < /proc/device-tree/chosen/os_prefix)" 289 | fi 290 | # set location for config.txt and cmdline.txt 291 | CMDLINE="/boot${FIRMWARE}/${PREFIX}cmdline.txt" 292 | CONFIG=/boot${FIRMWARE}/config.txt 293 | 294 | # check for existing install 295 | tashtalkInstalled= 296 | if [[ $(grep "dtoverlay=miniuart-bt" $CONFIG) && \ 297 | $(grep "gpio=16-17=a3" $CONFIG) && \ 298 | $(grep "enable_uart=1" $CONFIG) ]]; then 299 | tashtalkInstalled=1 300 | fi 301 | # check for serial port console 302 | consoleInstalled= 303 | if [[ $(grep "console=ttyAMA0" $CMDLINE) || \ 304 | $(grep "console=serial0" $CMDLINE) ]];then 305 | consoleInstalled=1 306 | fi 307 | [[ -f /tmp/a2server-autoAnswerYes ]] && autoAnswerYes=1 || autoAnswerYes= 308 | REPLY= 309 | if [[ ! $autoAnswerYes || -f /tmp/a2server-setupTashtalk ]]; then 310 | if [[ ! $tashtalkInstalled || $consoleInstalled ]];then 311 | echo 312 | echo "A2SERVER supports LocalTalk connectivity via a TashTalk Hat." 313 | echo "If you own one of these devices, you can set it up now." 314 | echo 315 | echo "NOTE: This will disable any serial consoles set up on this machine." 316 | echo "You will be prompted to reboot after A2SERVER setup to activate your TashTalk." 317 | echo 318 | echo -n "Do you want to setup a TashTalk Hat to use with A2SERVER? " 319 | read 320 | else 321 | echo "A2SERVER: TashTalk Hat already set up." 322 | sudo sed -i /usr/local/sbin/tashrouter.py -e "s/#from tashrouter.port.localtalk.tashtalk/from tashrouter.port.localtalk.tashtalk/" 323 | sudo sed -i /usr/local/sbin/tashrouter.py -e "s/#TashTalkPort/TashTalkPort/" 324 | fi 325 | fi 326 | if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then 327 | sudo true 328 | sudo apt-get install --no-install-recommends --assume-yes python3-serial 329 | # disable serial console 330 | sudo sed -i $CMDLINE -e "s/console=ttyAMA0,[0-9]\+ //" 331 | sudo sed -i $CMDLINE -e "s/console=serial0,[0-9]\+ //" 332 | 333 | # add required lines to config.txt 334 | if [[ ! $(grep "dtoverlay=miniuart-bt" $CONFIG) ]];then 335 | echo -e "dtoverlay=miniuart-bt" | sudo tee -a $CONFIG > /dev/null 336 | fi 337 | 338 | if [[ ! $(grep "gpio=16-17=a3" $CONFIG) ]];then 339 | echo -e "gpio=16-17=a3" | sudo tee -a $CONFIG > /dev/null 340 | fi 341 | 342 | if [[ $(grep "enable_uart=" $CONFIG) ]];then 343 | if [[ $(grep "enable_uart=0" $CONFIG) ]];then 344 | sudo sed -i $CONFIG -e "s/enable_uart=0/enable_uart=1/" 345 | fi 346 | else 347 | echo -e "enable_uart=1" | sudo tee -a $CONFIG > /dev/null 348 | fi 349 | 350 | # alter tashrouter configuration 351 | sudo sed -i /usr/local/sbin/tashrouter.py -e "s/#from tashrouter.port.localtalk.tashtalk/from tashrouter.port.localtalk.tashtalk/" 352 | sudo sed -i /usr/local/sbin/tashrouter.py -e "s/#TashTalkPort/TashTalkPort/" 353 | touch /tmp/rpiUpdate 354 | fi 355 | fi 356 | 357 | if [[ $(tac /usr/local/etc/netatalk/papd.conf | sed '/./,$!d' | head -1 | cut -c 1) == "#" ]]; then 358 | # enable papd's auto sharing of CUPS printer queues 359 | echo -e 'cupsautoadd:op=root:' | sudo tee -a /usr/local/etc/netatalk/papd.conf > /dev/null 360 | fi 361 | 362 | # Enable CUPS web interface and disable storing of old print jobs 363 | if [[ ! $(sudo grep "PreserveJobHistory No" /etc/cups/cupsd.conf) ]]; then 364 | sudo sed -i "/MaxLogSize/a PreserveJobHistory No" /etc/cups/cupsd.conf 365 | fi 366 | sudo cupsctl --remote-admin WebInterface=yes 367 | # Allow current user to add/remove CUPS printer queues 368 | sudo usermod -a -G lpadmin $USER 369 | 370 | # 1.3.0: we are no longer setting up new GSFILES 371 | # set up GSFILES share (for GS data files, not GSOS system) 372 | # classic Mac OS file names are allowed (31 chars, mixed case, everything but colons) 373 | #sudo sed -i \ 374 | # 's/^#share1/\/media\/A2SHARED\/GSFILES\ GSFILES ea:ad/' \ 375 | # /usr/local/etc/netatalk/AppleVolumes.default 376 | 377 | # 1.3.0: if GSFILES is being shared, make directory if not there 378 | if grep -q '^/srv/A2SERVER/GSFILES' /usr/local/etc/netatalk/AppleVolumes.default; then 379 | [[ -d /srv/A2SERVER/GSFILES ]] || mkdir -p /srv/A2SERVER/GSFILES; 380 | fi 381 | 382 | # prior to 1.3.0: 383 | # file names must be ProDOS 8 compliant (all caps, 15 chars, letters/numbers/periods only) 384 | # lowercase filenames will be converted to upper automatically 385 | # need for GS/OS system because it may refer to files by either upper or lower 386 | 387 | # 1.3.0+: 388 | # see if shared already uses ciopfs (case-insensitive file system), and convert if not 389 | # restore known GS/OS file paths to mixed case 390 | # set up ciopfs (case insensitive file system) for share 391 | if [[ -d /srv/A2SERVER/A2FILES && ! -d /srv/A2SERVER/.a2files ]]; then 392 | echo "A2SERVER: Converting A2FILES to support mixed case..." 393 | sudo /etc/init.d/netatalk stop &> /dev/null 394 | sudo /etc/init.d/samba stop &> /dev/null 395 | if ! hash getfattr &> /dev/null; then 396 | # Dependency: for ciopfs conversion (setfattr) 397 | sudo apt-get -y install attr &> /dev/null 398 | sudo apt-get clean 399 | fi 400 | rm /srv/A2SERVER/A2FILES/.APPLEDESKTOP 2> /dev/null 401 | mkdir -p /tmp/netboot 402 | wget -qO /tmp/A2FILES-list.txt ${binaryURL}A2FILES-list.txt 403 | find /srv/A2SERVER/A2FILES -name '*' | tail -n +2 | tac > /tmp/filelist.txt 404 | while read thisFile; do 405 | mixedCase="${thisFile##*/}" 406 | gsosPath=$(grep -i -m 1 "^${thisFile}$" /tmp/A2FILES-list.txt) 407 | [[ $gsosPath ]] && mixedCase="${gsosPath##*/}" 408 | sudo setfattr -n "user.filename" -v "$mixedCase" "$thisFile" 409 | if [[ ${thisFile##*/} != $mixedCase ]]; then 410 | echo -e " renaming $thisFile to ${mixedCase}\n" 411 | else 412 | echo -e " processing $thisFile\n" 413 | fi 414 | sudo mv "$thisFile" "${thisFile%/*}/${mixedCase,,}" 2> /dev/null 415 | done < /tmp/filelist.txt 416 | mv /srv/A2SERVER/A2FILES /srv/A2SERVER/.a2files 417 | mkdir /srv/A2SERVER/A2FILES 418 | sudo sed -i 's/casefold:toupper //' /usr/local/etc/netatalk/AppleVolumes.default 2> /dev/null 419 | sudo sed -i 's/^VOLCASEFOLD:.*/VOLCASEFOLD:/' /srv/A2SERVER/.a2files/.appledesktop/.volinfo 2> /dev/null 420 | sudo sed -i 's|/media/A2SHARED/A2FILES|/srv/A2SERVER/A2FILES|' /srv/A2SERVER/.a2files/.appledesktop/.volinfo 2> /dev/null 421 | fi 422 | 423 | # 1.3.0: remove GSFILES if empty 424 | if grep -q '^/srv/A2SERVER/GSFILES' /usr/local/etc/netatalk/AppleVolumes.default; then 425 | gsFilesContents= 426 | if [[ -d /srv/A2SERVER/GSFILES ]]; then 427 | 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$')" 428 | if [[ ! $gsFilesContents ]]; then 429 | echo "A2SERVER: Removing empty GSFILES shared volume..." 430 | sudo /etc/init.d/netatalk stop &> /dev/null 431 | sudo /etc/init.d/samba stop &> /dev/null 432 | sudo sed -i 's|^/srv/A2SERVER/GSFILES.*$|#share1|' /usr/local/etc/netatalk/AppleVolumes.default 433 | sudo rm -r /srv/A2SERVER/GSFILES 434 | else 435 | echo "A2SERVER: GSFILES shared volume has files, leaving as is." 436 | fi 437 | fi 438 | fi 439 | 440 | # set up A2FILES case-insensitive share (for ProDOS 8 files, and GS/OS system) 441 | sudo sed -i \ 442 | 's/^#share2/\/srv\/A2SERVER\/A2FILES\ A2FILES options:prodos\ ea:ad/' \ 443 | /usr/local/etc/netatalk/AppleVolumes.default 444 | [[ -d /srv/A2SERVER/A2FILES ]] || mkdir -p /srv/A2SERVER/A2FILES 445 | [[ -d /srv/A2SERVER/.a2files ]] || mkdir -p /srv/A2SERVER/.a2files 446 | 447 | # set up ciopfs 448 | if ! hash ciopfs &> /dev/null; then 449 | echo "A2SERVER: Installing ciopfs (case insensitive file system)..." 450 | cd /tmp 451 | 452 | # Dependency: For ciopfs 453 | sudo apt-get -y install fuse libglib2.0-0 libattr1 libfuse2 454 | if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then 455 | { wget -qO- "${binaryURL}precompiled/ciopfs-${arch}.tgz" | sudo tar Pzx; } &> /dev/null 456 | fi 457 | if [[ -f /etc/fuse.conf ]] && sudo grep -q user_allow_other /etc/fuse.conf; then 458 | sudo sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf 459 | else 460 | echo "user_allow_other" | sudo tee /etc/fuse.conf > /dev/null 461 | fi 462 | 463 | if ! hash ciopfs &> /dev/null; then 464 | if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then 465 | # prepare for installing packages 466 | sudo apt-get -y update 467 | touch /tmp/a2server-packageReposUpdated 468 | fi 469 | 470 | # Dependency: build-dep for ciopfs 471 | sudo apt-get -y install build-essential libfuse-dev libglib2.0-dev libattr1-dev 472 | sudo apt-get -y clean 473 | 474 | cd /tmp 475 | rm -rf /tmp/ciopfs &> /dev/null 476 | mkdir /tmp/ciopfs 477 | cd /tmp/ciopfs 478 | if [[ $useExternalURL ]]; then 479 | wget -q -O ciopfs-0.4.tar.gz http://www.brain-dump.org/projects/ciopfs/ciopfs-0.4.tar.gz 480 | if (( $? != 0 )); then 481 | wget -q -O ciopfs-0.4.tar.gz http://web.archive.org/web/20160911102924/http://www.brain-dump.org/projects/ciopfs/ciopfs-0.4.tar.gz 482 | fi 483 | tar zxf ciopfs-0.4.tar.gz &> /dev/null 484 | rm ciopfs-0.4.tar.gz &> /dev/null 485 | fi 486 | if [ ! -f ciopfs*/ciopfs.c ]; then # single brackets required for glob 487 | wget -q -O ciopfs-0.4.tar.gz ${binaryURL}external/source/ciopfs-0.4.tar.gz 488 | tar zxf ciopfs-0.4.tar.gz &> /dev/null 489 | rm ciopfs-0.4.tar.gz &> /dev/null 490 | fi 491 | cd ciopfs* 492 | make 493 | sudo mv ciopfs /usr/local/bin 494 | cd 495 | rm -rf /tmp/ciopfs 496 | fi 497 | if ! grep -q '^ciopfs' /etc/fstab; then 498 | echo "ciopfs#/srv/A2SERVER/.a2files /srv/A2SERVER/A2FILES fuse allow_other 0 0" | sudo tee -a /etc/fstab > /dev/null 499 | fi 500 | if ! mount | grep '^ciopfs.*A2FILES'; then 501 | sudo ciopfs /srv/A2SERVER/.a2files /srv/A2SERVER/A2FILES -o allow_other 502 | fi 503 | sudo systemctl daemon-reload 504 | else 505 | echo "A2SERVER: ciopfs (case insensitive file system) has already been installed." 506 | fi 507 | 508 | if [[ ! -d /srv/A2SERVER/A2FILES/.AppleDesktop ]]; then 509 | cd /srv/A2SERVER/A2FILES 510 | mkdir .AppleDesktop 511 | fi 512 | 513 | # set up ADTDISKS share (ADTPro disk image folder, if A2CLOUD is installed) 514 | # classic Mac OS file names are allowed (31 chars, mixed case, everything but colons) 515 | if [[ -d /usr/local/adtpro/disks ]]; then # A2CLOUD/ADTPro installed 516 | if [[ ! -d /srv/A2SERVER/ADTDISKS ]]; then 517 | ln -s /usr/local/adtpro/disks /srv/A2SERVER/ADTDISKS 518 | fi 519 | if [[ ! $(grep ADTDISKS /usr/local/etc/netatalk/AppleVolumes.default) ]]; then 520 | sudo sed -i 's@^# End of File@/srv/A2SERVER/ADTDISKS ADTDISKS ea:ad\n\n# End of File@' /usr/local/etc/netatalk/AppleVolumes.default 521 | fi 522 | fi 523 | 524 | 525 | 526 | # prepare shared volumes for use 527 | afpsync -v < /dev/null 528 | 529 | # --- Setting up users 530 | 531 | # At this point, the server is usable for Guest access. 532 | 533 | # skip if we've already done this 534 | if [[ -f /usr/local/etc/netatalk/afppasswd ]]; then 535 | 536 | echo "A2SERVER: Netatalk user logins have already been set up." 537 | 538 | else 539 | 540 | echo 541 | echo "A2SERVER: Setting up AFP password 'apple2' for Apple II and Mac clients..." 542 | # echo "A2SERVER: Enter 'apple2' or another password of up to eight characters." 543 | echo 544 | # set registered user login using RandNum authentication 545 | sudo afppasswd -c 546 | sudo sed -i "s/^\(${USER}\).*$/\1:6170706C65320000:****************:********/" /usr/local/etc/netatalk/afppasswd 547 | # (The afppasswd -c only needs to ever be done once. You can repeat 548 | # the afppasswd -a to make Netatalk randnum logins for other Linux users.) 549 | 550 | fi 551 | 552 | # Check AppleTalk kernel module for existence and validity 553 | 554 | # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) 555 | kernelRelease=$(uname -r) 556 | kernelMajor=$(cut -d '.' -f 1 <<< $kernelRelease) 557 | kernelMinor=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') 558 | kernelPatch=$(cut -d '.' -f 3- <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') 559 | kernelMajorMinor=$(cut -d '.' -f 1-2 <<< $kernelRelease) 560 | 561 | # if IPDDP module exists (e.g. Debian, but not Raspbian), 562 | # AppleTalk kernel module has been compiled to support it and can't work with MacIP 563 | if [[ -f "/lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko" ]]; then 564 | sudo systemctl stop atalkd afpd papd a2boot timelord macipgw &> /dev/null 565 | sudo rmmod ipddp 2> /dev/null 566 | sudo rmmod appletalk 2> /dev/null 567 | echo "A2SERVER: Replacing AppleTalk kernel module (IPDDP disabled) for MacIP use..." 568 | 569 | sudo mv /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko /tmp 2> /dev/null 570 | 571 | if [[ ! $compileFromSource && ${arch%_*} == "debian" ]]; then 572 | echo "A2SERVER: Fetching AppleTalk kernel module for Debian..." 573 | wget -qO /tmp/appletalk.tgz ${binaryURL}precompiled/appletalk-$kernelRelease-${arch}.tgz 574 | if [[ $? -eq 0 ]]; then 575 | # if we found a prebuilt one on a2server site, install it and load it 576 | sudo tar Pxf /tmp/appletalk.tgz &> /dev/null 577 | sudo depmod 578 | sudo modprobe appletalk 579 | if [[ $(lsmod | grep appletalk) ]]; then 580 | # if it loaded, restart netatalk 581 | sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk 582 | sudo /etc/init.d/netatalk restart &> /dev/null 583 | else 584 | echo "A2SERVER: failed to load AppleTalk kernel module" 585 | # if we didn't load it successfully, remove it 586 | sudo rm /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko 2> /dev/null 587 | fi 588 | else # download failed, so premade kernel not found, remove empty file 589 | rm /tmp/appletalk.tgz 2>/dev/null 590 | fi 591 | fi 592 | 593 | if ! lsmod | grep -q appletalk; then 594 | # we don't have a prebuilt AppleTalk module, try to build from source 595 | if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then 596 | # prepare for installing packages 597 | sudo apt-get -y update 598 | touch /tmp/a2server-packageReposUpdated 599 | fi 600 | 601 | # kernel module compile adapted from from: http://askubuntu.com/a/338403/288003 602 | for i in 1; do 603 | echo "A2SERVER: Building AppleTalk kernel module..." 604 | [[ -f /boot/config-$kernelRelease ]] || break 605 | sudo apt-get -y install linux-headers-$kernelRelease linux-source-$kernelMajorMinor || break 606 | sudo apt-get -y install build-essential 607 | sudo apt-get -y install libelf-dev # required as of kernel 4.14.12, apparently 608 | cd /usr/src 609 | kernelSrc=$(find linux-source-${kernelMajorMinor}*) 610 | if [[ ${kernelSrc##*.} == "xz" ]]; then 611 | { xzcat $kernelSrc | sudo tar x; } &> /dev/null 612 | elif [[ ${kernelSrc##*.} == "bz2" ]]; then 613 | sudo tar jxf $kernelSrc &> /dev/null 614 | elif [[ ${kernelSrc##*.} == "gz" || ${kernelSrc##*.} == "tgz" ]]; then 615 | sudo tar zxf $kernelSrc &> /dev/null 616 | fi 617 | cd linux-source-$kernelMajorMinor 618 | sudo make mrproper 619 | sudo cp ../linux-headers-$kernelRelease/Module.symvers . 620 | yes '' | sudo make oldconfig 621 | sudo sed -i 's:^.*IPDDP.*$:# CONFIG_IPDDP is not set:gI' .config # disable IPDDP in kernel config 622 | sudo sed -i '$!N; /^\(# CONFIG_IPDDP is not set\)\n\1$/!P; D' .config # delete repeated entries 623 | sudo make prepare 624 | sudo make modules_prepare 625 | sudo make M=net/appletalk 626 | sudo cp net/appletalk/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk 627 | sudo depmod 628 | sudo modprobe appletalk 629 | sudo rm -r /lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko 630 | sudo rmdir /lib/modules/$kernelRelease/kernel/drivers/net/appletalk 2> /dev/null 631 | 632 | # clean up 633 | cd 634 | sudo rm /usr/src/$kernelSrc 635 | sudo rm -r /usr/src/linux-source-$kernelMajorMinor 636 | sudo apt-get -y purge linux-source-$kernelMajorMinor 637 | sudo apt -y autoremove 638 | done 639 | fi 640 | 641 | if [[ $(lsmod | grep appletalk) ]]; then 642 | # if it loaded, make permanent and restart netatalk 643 | sudo rm /lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko 2> /dev/null 644 | sudo sed -i 's:^.*IPDDP.*$:# CONFIG_IPDDP is not set:gI' /boot/config-$kernelRelease 645 | sudo sed -i '$!N; /^\(# CONFIG_IPDDP is not set\)\n\1$/!P; D' /boot/config-$kernelRelease 646 | else 647 | # if we didn't load it successfully, put back the one that was there 648 | echo "A2SERVER: Unable to replace AppleTalk module, replacing original." 649 | sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null 650 | sudo depmod 651 | touch /tmp/noMacIP # to notify at end of install 652 | fi 653 | fi 654 | 655 | # --- Start Netatalk (if not running) 656 | 657 | sudo systemctl start atalkd afpd papd a2boot timelord macipgw tashrouter 2> /dev/null 658 | 659 | echo 660 | echo "A2SERVER: Netatalk is installed, configured, and running." 661 | echo 662 | 663 | # if atalkd isn't running (no AppleTalk), and this is a Rasbperry Pi: 664 | if [[ ( ! $(ps aux | grep [a]talkd) ) && ( $isRpi ) ]]; then 665 | 666 | # if AppleTalk module exists, try to load it 667 | if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # module present, but not loaded? 668 | sudo depmod 669 | sudo modprobe appletalk 670 | if [[ $(lsmod | grep appletalk) ]]; then 671 | # if it loaded, restart netatalk 672 | sudo systemctl restart atalkd afpd papd a2boot timelord macipgw 2> /dev/null 673 | else 674 | # if we didn't load it successfully, delete it 675 | sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk 676 | fi 677 | fi 678 | 679 | # if no AppleTalk module, try to download it from a2server site 680 | if [[ ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # check for rpi kernel module 681 | echo "A2SERVER: Installing AppleTalk kernel module for Raspbian..." 682 | wget -qO /tmp/appletalk.ko.gz ${binaryURL}appletalk-$kernelRelease-rpi.ko.gz 683 | if [[ $? -eq 0 ]]; then 684 | # if we found a prebuilt one on a2server site, install it and load it 685 | gunzip -f /tmp/appletalk.ko.gz &> /dev/null 686 | sudo mkdir -p /lib/modules/$kernelRelease/kernel/net/appletalk 687 | sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk 688 | sudo depmod 689 | sudo modprobe appletalk 690 | if [[ $(lsmod | grep appletalk) ]]; then 691 | # if it loaded, restart netatalk 692 | sudo systemctl restart atalkd afpd papd a2boot timelord macipgw 2> /dev/null 693 | else 694 | # if we didn't load it successfully, remove it 695 | sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null 696 | fi 697 | fi 698 | 699 | if [[ ! $(ps aux | grep [a]talkd) ]]; then 700 | if [[ -f /tmp/rpiUpdate ]]; then 701 | echo 702 | echo "AppleTalk networking is installed but not yet active." 703 | echo "When installation is complete, please restart your Raspberry Pi" 704 | echo "when asked or by typing 'system-restart' at the Linux prompt" 705 | echo "to allow Apple II computers to connect." 706 | echo 707 | else 708 | echo 709 | echo "AppleTalk networking could not be activated" 710 | echo "for your Raspbian kernel version ($kernelRelease)." 711 | echo "Please try restarting with 'system-restart'. If that doesn't work," 712 | echo "you're not going to be able to connect from an Apple II." 713 | echo "See http://appleii.ivanx.com/a2server for help." 714 | echo 715 | fi 716 | fi 717 | fi 718 | fi 719 | 720 | # --- Set up Avahi-Daemon (Bonjour/mDNS) 721 | # thanks to: http://missingreadme.wordpress.com/2010/05/08/how-to-set-up-afp-filesharing-on-ubuntu 722 | 723 | if [[ ! $(dpkg -l avahi-daemon 2> /dev/null | grep ^ii) || ! $(dpkg -l libnss-mdns 2> /dev/null | grep ^ii) ]]; then 724 | echo "A2SERVER: Installing Avahi-Daemon (Bonjour/mDNS)..." 725 | if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then 726 | # prepare for installing packages 727 | sudo apt-get -y update 728 | touch /tmp/a2server-packageReposUpdated 729 | fi 730 | 731 | # Dependency: Bonjour for netatalk 732 | sudo apt-get -y install avahi-daemon libnss-mdns &> /dev/null 733 | 734 | fi 735 | sudo sed -i 's/^\(hosts.*\)$/\1 mdns/' /etc/nsswitch.conf 736 | if [[ ! -f /etc/avahi/services/afpd.service && ! -f /etc/avahi/services/afpd.service_disabled ]]; then 737 | 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 738 | fi 739 | sudo systemctl restart avahi-daemon &> /dev/null 740 | -------------------------------------------------------------------------------- /scripts/a2server-6-samba.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # Set up A2SERVER to support Samba (Windows File Sharing) 5 | # this script can also be used if new shares are introduced 6 | 7 | [[ -f /tmp/a2server-autoAnswerYes ]] && autoAnswerYes=1 || autoAnswerYes= 8 | 9 | if [[ ! $autoAnswerYes || -f /tmp/a2server-setupWindowsSharing ]]; then 10 | 11 | if [[ ! $autoAnswerYes ]]; then 12 | echo 13 | echo -n "Should Windows computers be able to connect to A2SERVER? " 14 | read 15 | fi 16 | if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then 17 | 18 | echo "A2SERVER: Setting up Windows file sharing..." 19 | sudo true 20 | 21 | [[ ! -f /etc/init.d/smbd ]] && installSamba=1 22 | 23 | if (( $installSamba )); then 24 | if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then 25 | # prepare for installing packages 26 | sudo apt-get -y update 27 | touch /tmp/a2server-packageReposUpdated 28 | fi 29 | 30 | # Dependency: samba for Windows/modern Macs 31 | # FIXME: Figure out when smbpasswd moved and adjust this as necessary 32 | sudo apt-get -y install samba 33 | hash smbpasswd &> /dev/null || sudo apt-get -y install samba-common-bin 34 | sudo apt-get clean 35 | fi 36 | 37 | sudo systemctl start smbd nmbd &> /dev/null 38 | sudo systemctl enable smbd nmbd &> /dev/null 39 | 40 | workgroup=$(grep -o "^ workgroup = .*$" /etc/samba/smb.conf 2> /dev/null | cut -c 16-) 41 | [[ $workgroup ]] || workgroup="WORKGROUP" 42 | if [[ ! $autoAnswerYes ]]; then 43 | echo 44 | echo "Enter workgroup name (or press return for '${workgroup}'): " 45 | read 46 | [[ $REPLY ]] && workgroup=$REPLY 47 | fi 48 | sudo sed -i 's/^ workgroup = .*$/ workgroup = '$workgroup'/' /etc/samba/smb.conf 2> /dev/null 49 | sudo sed -i 's/^# security = user/ security = user/' /etc/samba/smb.conf 2> /dev/null 50 | 51 | # remove GSFILES if no longer serving it 52 | if ! grep ^/srv/A2SERVER/GSFILES /usr/local/etc/netatalk/AppleVolumes.default; then 53 | sudo sed -i ':a;N;$!ba;s#\n\[GSFILES\].*\[#\n[#' /etc/samba/smb.conf 54 | sudo sed -i ':a;N;$!ba;s#\n\[GSFILES\].*$#\n#' /etc/samba/smb.conf 55 | fi 56 | 57 | grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | cut -d" " -f2 \ 58 | | while read sharename; do 59 | if [[ $(grep $sharename /etc/samba/smb.conf) ]]; then 60 | echo "A2SERVER: $sharename is already set up for Windows file sharing." 61 | else 62 | echo "[$sharename]" | sudo tee -a /etc/samba/smb.conf > /dev/null 63 | echo " path = /srv/A2SERVER/$sharename" | sudo tee -a /etc/samba/smb.conf > /dev/null 64 | echo " browsable = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null 65 | echo " guest ok = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null 66 | echo " read only = no" | sudo tee -a /etc/samba/smb.conf > /dev/null 67 | echo " create mask = 0666" | sudo tee -a /etc/samba/smb.conf > /dev/null 68 | echo " force user = $USER" | sudo tee -a /etc/samba/smb.conf > /dev/null 69 | echo "A2SERVER: $sharename has been set up for Windows file sharing." 70 | fi 71 | done 72 | 73 | echo 74 | echo "A2SERVER: Setting Windows file sharing password to 'apple2'." 75 | echo -e 'apple2\napple2' | sudo smbpasswd -s -a $USER 76 | 77 | echo 78 | echo "A2SERVER: Windows file sharing is now running." 79 | else 80 | sudo systemctl stop smbd nmbd &> /dev/null 81 | sudo systemctl disable smbd nmbd &> /dev/null 82 | echo "A2SERVER: Windows file sharing has been turned off." 83 | fi 84 | 85 | echo 86 | fi 87 | -------------------------------------------------------------------------------- /scripts/a2server-7-console.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # This script helps when running on the Linux console within a VirtualBox VM. 5 | 6 | echo 7 | 8 | userPw=$(sudo grep "^$USER" /etc/shadow | cut -f 2 -d ':') 9 | [[ $userPw == "$(echo 'apple2' | perl -e '$_ = ; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isApple2Pw=1 || isApple2Pw= 10 | [[ $userPw == "$(echo 'raspberry' | perl -e '$_ = ; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isRaspberryPw=1 || isRaspberryPw= 11 | 12 | password="your password" 13 | [[ $isApple2Pw ]] && password="'apple2'" 14 | [[ $isRaspberryPw ]] && password="'raspberry'" 15 | 16 | isDebian= 17 | 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 18 | 19 | if [[ $isDebian ]]; then 20 | if { lspci 2> /dev/null | grep -q VirtualBox; }; then 21 | echo "A2SERVER: Disabling VirtualBox console screen blanking..." 22 | sudo sed -i 's/^BLANK_DPMS=off/BLANK_DPMS=on/' /etc/kbd/config 23 | sudo sed -i 's/^BLANK_TIME=[^0].$/BLANK_TIME=0/' /etc/kbd/config 24 | sudo /etc/init.d/kbd restart &> /dev/null 25 | sudo /etc/init.d/console-setup restart &> /dev/null 26 | fi 27 | fi 28 | -------------------------------------------------------------------------------- /scripts/clock.patch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | '''CLOCK.PATCH by Greg Branche implemented in Python 2/3 for A2SERVER 3 | 4 | This is a line-for-line conversion of an edited version of CLOCK.PATCH 5 | from the System Tools 2 disk in GS/OS 6.0.1. It's not good Python, 6 | but I thought it would be an interesting exercise. In general 7 | I have tried replicate each line as closely to BASIC as possible. 8 | 9 | Because BASIC substrings are 1-based and python's are 0-based, various 10 | indexes are minus one of their BASIC equivalents. 11 | 12 | The one change is that you can optionally pass the day and date by 13 | command line argument (e.g "Wed 3/13/15"). I also improved error 14 | checking. These are in the BASIC lines that don't end in 0. 15 | 16 | Rather than modifying PRODOS, this outputs a string of comma-separated 17 | year values for a calling script (the a2server-setup installer), 18 | followed by a space and a dd-Mmm-yy date string. 19 | ''' 20 | 21 | # imports for python 3 code compatibility 22 | from __future__ import print_function 23 | from __future__ import unicode_literals 24 | from __future__ import absolute_import 25 | from __future__ import division 26 | 27 | # other imports 28 | import sys 29 | import datetime 30 | 31 | # substitute raw_input for input in Python2 32 | try: input = raw_input 33 | except NameError: pass 34 | 35 | dow_str = None 36 | day = None 37 | if len(sys.argv) > 2: 38 | dow_str = sys.argv[1] # day of week passed on command line 39 | day = sys.argv[2] # date passed on command line 40 | 41 | # 60000 REM # of days in each month 42 | data = [31,28,31,30,31,30,31,31,30,31,30] # 60010 DATA 31,28,31,30,31,30,31,31,30,31,30 43 | # 60020 REM Names of days of week 44 | data += [ # 60030 DATA SUN,MON,TUE,WED,THU,FRI,SAT 45 | "SUN","MON","TUE","WED","THU","FRI","SAT"] 46 | data = iter(data) 47 | # 110 REM cu() = cumulative # of days in year 48 | cu = [0] * 13 # 120 DIM CU(12) 49 | # 130 REM fill array with # of days in year 50 | cu[1] = 0 # 140 CU(1) = 0: REM January 51 | for i in range(2,13): # 150 FOR I = 2 TO 12 52 | x = next(data) # 160 READ X 53 | cu[i] = cu[i-1] + x # 170 CU(I) = CU(I - 1) + X 54 | # 180 NEXT I 55 | 56 | # 200 REM DN$() = Names for days of week 57 | dn = [""] * 8 # 210 DIM DN$(7) 58 | # 220 REM fill array with names of days of week 59 | for i in range(1,8): # 230 FOR I = 1 TO 7 60 | dn[i] = next(data) # 240 READ DN$(I) 61 | # 250 NEXT I 62 | 63 | # 270 REM yt() is the year table values 64 | yt = [0] * 8 # 280 DIM YT(7) 65 | 66 | def mod7(x): # 340 DEF FN MOD7(X) = INT (((X / 7) - INT (X / 7)) * 7 + .5) 67 | return int(((x / 7) - int(x / 7)) * 7 + .5) 68 | 69 | def find_slash_pos(day): # 799 REM Finds position of / within date string 70 | x = -1 # 800 X = 0: REM On exit, contains position of /, or 0 if none found 71 | for i in range(0,3): # 810 FOR I = 1 TO 3 72 | if day[i:i+1] == "/": x = i; break # 820 IF MID$ (DAY$,I,1) = "/" THEN X = I:I = 3 73 | # 830 NEXT I 74 | return x # 840 RETURN 75 | 76 | while True: # 999 REM get the user's input and convert 77 | if not day: 78 | print( # 1010 PRINT "Please enter today's date (mm/dd/yy)" 79 | "Please enter today's date (mm/dd/yy)") 80 | day = input("-> ") # 1020 INPUT "-> ";DAY$ 81 | x = find_slash_pos(day) # 1030 GOSUB 800: REM find slash separator 82 | input_ok = False 83 | while not input_ok: 84 | if not (x != -1): # 1040 IF X < > 0 THEN 1080 85 | print( # 1050 PRINT "Invalid date entered. Please try again."; CHR$ (7) 86 | "Invalid date entered. Please try again.\x07") 87 | break # 1060 GOTO 1010 88 | # 1070 REM Convert month value to numeric variable 89 | mo = int(day[0:0+x]) # 1080 MO = VAL ( MID$ (DAY$,1,X - 1)) 90 | day = day[x+1:] # 1090 DAY$ = MID$ (DAY$,X + 1) 91 | if mo < 1 or mo > 12: x = -1; continue # 1100 IF MO < 1 OR MO > 12 THEN 1050: REM Range check the month value 92 | x = find_slash_pos(day) # 1110 GOSUB 800: REM Parse out the current day 93 | if x == -1: continue # 1120 IF X = 0 THEN 1050 94 | # 1130 REM Convert day string into numeric value 95 | da = int(day[0:0+x]) # 1140 DA = VAL ( MID$ (DAY$,1,X - 1)) 96 | day = day[x+1:] # 1150 DAY$ = MID$ (DAY$,X + 1) 97 | if da < 1 or da > 31: x = -1; continue # 1160 IF DA < 1 OR DA > 31 THEN 1050: REM Range check the day value 98 | if mo == 2 and da > 29: # 1161 IF MO = 2 AND DA > 29 THEN 1050 99 | x = -1; continue 100 | if (mo == 4 or # 1162 IF (MO = 4 OR MO = 6 OR MO = 9 OR MO = 11) AND DA > 30 THEN 1050 101 | mo == 6 or 102 | mo == 9 or 103 | mo == 11) and da > 30: x = -1; continue 104 | # 1170 REM Convert year string into numeric value 105 | yr = int(day) # 1180 YR = VAL (DAY$) 106 | if yr < 0 or yr > 99: x = -1; continue # 1190 IF YR < 0 OR YR > 99 THEN 1050: REM Only allow 0-99 107 | if yr > 39: yr = yr + 1900 # 1200 IF YR > 39 THEN YR = YR + 1900: REM 40-99 must be 1940-1999 108 | if yr < 40: yr = yr + 2000 # 1210 IF YR < 40 THEN YR = YR + 2000: REM 0-39 must be 2000-2039 109 | if ((yr / 4) != int(yr / 4) and # 1211 IF ((YR / 4) < > INT(YR / 4)) AND MO = 2 AND DA > 28 THEN 1050 110 | mo == 2 and 111 | da > 28): x = -1; continue 112 | input_ok = True 113 | if x != -1: break 114 | else: dow_str = ""; day = "" 115 | 116 | while True: 117 | if not dow_str: 118 | print( 119 | "Please enter the day of the week") # 1230 PRINT "Please enter the day of the week" 120 | dow_str = input("(e.g. Wed) -> ") # 1240 INPUT "(e.g. Wed) -> ";DOW$ 121 | input_ok = False 122 | while not input_ok: 123 | if not (len(dow_str) >= 3): # 1250 IF LEN (DOW$) > = 3 THEN 1270: REM Must be at least 3 characters 124 | print( # 1260 PRINT "Invalid day of week. Please try again."; CHR$ (7): GOTO 1230 125 | "Invalid day of week. Please try again.\x07") 126 | break 127 | if len(dow_str) > 3: # 1270 IF LEN (DOW$) > 3 THEN DOW$ = LEFT$ (DOW$,3) 128 | dow_str = dow_str[0:0+3] 129 | # 1280 REM Shift any lower case letters to upper case 130 | b = "" # 1290 B$ = "" 131 | for i in range(0,3): # 1300 FOR I = 1 TO 3 132 | a = dow_str[i:i+1] # 1310 A$ = MID$ (DOW$,I,1) 133 | if ( # 1320 IF ASC (A$) > = ASC ("a") AND ASC (A$) < = ASC ("z") THEN A$ = CHR$ ( ASC (A$) - ( ASC ("a") - ASC ("A"))) 134 | ord(a) >= ord("a") and ord(a) <= ord("z")): a = chr(ord(a) - (ord("a") - ord("A"))) 135 | b = b + a # 1330 B$ = B$ + A$ 136 | # 1340 NEXT I 137 | dow_str = b # 1350 DOW$ = B$ 138 | # 1360 REM Now convert day-of-week string to numeric value 139 | dow_num = 0 # 1370 DOW = 0 140 | for i in range (1,8): # 1380 FOR I = 1 TO 7 141 | if dow_str == dn[i]: # 1390 IF DOW$ = DN$(I) THEN DOW = I:I = 7 142 | dow_num = i; i = 7 143 | # 1400 NEXT I 144 | if dow_num == 0: dow_str = ""; continue # 1410 IF DOW = 0 THEN 1260 145 | input_ok = True 146 | if len(dow_str) >= 3: break 147 | else: dow_str = ""; day = "" 148 | # 1430 REM Calculate the number of days so far this year 149 | dys = da + cu[mo] # 1440 DYS = DA + CU(MO) 150 | oyr = yr 151 | # 1450 REM Must account for extra day in leap year 152 | if ((yr / 4) == int(yr / 4)) and (mo > 2): # 1460 IF (YR / 4) = INT (YR / 4) AND MO > 2 THEN DYS = DYS + 1 153 | dys = dys + 1 154 | 155 | # 1480 REM Now calculate the index to use to fill in the table 156 | idx = dow_num - mod7(dys) + 1 # 1490 IDX = DOW - FN MOD7(DYS) + 1 157 | idx = abs(idx - 10) # 1500 IDX = ABS (IDX - 10) 158 | if idx > 7: idx = idx - 7 # 1510 IF IDX > 7 THEN IDX = IDX - 7 159 | 160 | # 1530 REM Now we can fill in the year table 161 | for i in range(1,8): # 1540 FOR I = 1 TO 7 162 | if '_i' in vars() and i < (_i + 1): continue # python: simulate change of i within loop 163 | x = yr - 1900 # 1550 X = YR - 1900 164 | if x >= 100: x = x - 100 # 1560 IF X > = 100 THEN X = X - 100 165 | yt[idx] = x # 1570 YT(IDX) = X: REM store the year into table 166 | idx = idx - 1 # 1580 IDX = IDX - 1 167 | if idx < 1: idx = 7 # 1590 IF IDX < 1 THEN IDX = 7 168 | if not ((yr / 4) != int(yr / 4)): # 1600 IF (YR / 4) < > INT (YR / 4) THEN 1660: REM not a leap year 169 | i = i + 1; _i = i # 1610 I = I + 1: REM update index 170 | if i > 7: continue # 1620 IF I > 7 THEN 1670: REM if entire array done, exit 171 | yt[idx] = x # 1630 YT(IDX) = X: REM duplicate entry for leap year 172 | idx = idx - 1 # 1640 IDX = IDX - 1 173 | if idx < 1: idx = 7 # 1650 IF IDX < 1 THEN IDX = 7 174 | yr = yr + 1 # 1660 YR = YR + 1 175 | # 1670 NEXT I 176 | 177 | print(",".join([str(x) for x in yt[1:]]) + " " + 178 | str(da).encode("L1").decode("L1").zfill(2) + "-" + 179 | datetime.date(1900, mo, 1).strftime('%b') + "-" + 180 | str(oyr).encode("L1").decode("L1")[2:]) 181 | -------------------------------------------------------------------------------- /scripts/raspbian-update.txt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # raspbian-update 4 | # updates Raspbian to latest version, including NOOBS if installed 5 | 6 | [[ -f /usr/bin/raspi-config ]] && isRpi=1 || isRpi= 7 | 8 | if [[ ! $isRpi ]]; then 9 | echo "This ain't a Raspberry Pi." 10 | [[ $0 == "-bash" ]] && return 1 || exit 1 11 | fi 12 | 13 | skipRepoUpdate= 14 | autoYes= 15 | updateA2Cloud= 16 | updateA2Server= 17 | while [[ $1 ]]; do 18 | if [[ $1 == "-r" ]]; then 19 | shift 20 | skipRepoUpdate="-r" 21 | elif [[ $1 == "-y" ]]; then 22 | shift 23 | autoYes="-y" 24 | elif [[ $1 == "-n" ]]; then 25 | shift 26 | noobsOnly="-n" 27 | elif [[ $1 == "a2cloud" ]]; then 28 | shift 29 | updateA2Cloud=1 30 | elif [[ $1 == "a2server" ]]; then 31 | shift 32 | updateA2Server=1 33 | elif [[ $1 ]]; then 34 | echo "options:" 35 | echo "-y: auto-answer yes to all prompts and don't prompt for restart" 36 | echo "-r: don't update package repositories" 37 | echo "-n: update NOOBS only; don't update Raspbian" 38 | echo "a2cloud : update A2CLOUD when complete" 39 | echo "a2server: update A2SERVER when complete" 40 | [[ $0 == "-bash" ]] && return 1 || exit 1 41 | fi 42 | done 43 | 44 | noobs= 45 | readarray -t partitions < <(sudo fdisk -l | grep '^/dev') 46 | if [[ \ 47 | ${partitions[0]:0:14} == "/dev/mmcblk0p1" && ${partitions[0]:57:2} == " e" && 48 | ${partitions[1]:0:14} == "/dev/mmcblk0p2" && ${partitions[1]:57:2} == "85" && 49 | ${partitions[2]:0:14} == "/dev/mmcblk0p3" && ${partitions[2]:57:2} == "83" && 50 | ${partitions[3]:0:14} == "/dev/mmcblk0p5" && ${partitions[3]:57:2} == " c" && 51 | ${partitions[4]:0:14} == "/dev/mmcblk0p6" && ${partitions[4]:57:2} == "83" ]]; then 52 | noobs=" and the NOOBS install manager" 53 | fi 54 | 55 | if [[ ! $autoYes ]]; then 56 | echo 57 | echo "You are about to update your SD card to the latest version of the" 58 | echo "Raspbian operating system${noobs}." 59 | echo 60 | echo "This may take an hour or more, and will require restarting when complete." 61 | echo "You might want a backup before continuing in case it doesn't go as planned." 62 | echo 63 | echo -n "Update Raspbian? " 64 | read 65 | if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then 66 | [[ $0 == "-bash" ]] && return 2 || exit 2 67 | fi 68 | fi 69 | 70 | origDir="$PWD" 71 | cd /tmp 72 | 73 | if [[ ! $skipRepoUpdate ]]; then 74 | echo "Updating package repositories..." 75 | sudo apt-get -y update > /dev/null 76 | else 77 | echo "Not updating package repositories..." 78 | echo 79 | fi 80 | 81 | if [[ ! $noobsOnly ]]; then 82 | { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null 83 | freeSpace=$(df / | tail -1 | awk '{ print $4 }') 84 | if (( $freeSpace < 400000 )); then 85 | if dpkg -l | grep -q wolfram-engine; then 86 | if [[ ! $autoYes ]]; then 87 | echo "In order to create enough space on your SD card to upgrade," 88 | echo "the Wolfram Language and Mathematica software packages must be removed." 89 | echo "If you don't know what these are, this won't affect you at all." 90 | echo 91 | echo -n "Remove Wolfram software? " 92 | read 93 | if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then 94 | [[ $0 == "-bash" ]] && return 2 || exit 2 95 | fi 96 | sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null 97 | sudo apt-get -y purge wolfram-engine 98 | else 99 | echo "Removing Wolfram software due to space constraints..." 100 | sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null 101 | sudo apt-get -y purge wolfram-engine 102 | fi 103 | else 104 | echo "You don't have enough free space on your SD card to upgrade." 105 | echo "Sorry, man. Delete some stuff or get a bigger card." 106 | [[ $0 == "-bash" ]] && return 1 || exit 1 107 | fi 108 | fi 109 | 110 | { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null 111 | dpkg -l | grep -q a2pi && sudo apt-get -y --force-yes install a2pi 112 | dpkg -l | grep -q apple2user && sudo apt-get -y --force-yes install apple2user gsport 113 | if dpkg -l | grep -q wolfram-engine; then 114 | sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null 115 | if [[ $freeSpace -lt 750000 && $(apt-get -s install wolfram-engine | grep upgraded) ]]; then 116 | sudo apt-get -y purge wolfram-engine 117 | { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null 118 | fi 119 | sudo apt-get -y install wolfram-engine 120 | { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null 121 | fi 122 | sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade 123 | { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null 124 | sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade 125 | { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null 126 | sudo apt-get -y install raspberrypi-ui-mods 127 | { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null 128 | fi 129 | 130 | if [[ $noobs ]]; then 131 | echo "Updating NOOBS..." 132 | 133 | # update Partition 3 134 | mkdir -p /tmp/p3 135 | sudo mount /dev/mmcblk0p3 /tmp/p3 136 | sudo rm -rf /tmp/p3/os/* 2> /dev/null 137 | if grep -q 'Raspple II' /tmp/p3/installed_os.json; then 138 | echo "Downloading Raspple II lite..." 139 | noobsUrl="ivanx.com/rasppleii/files/RasppleII_lite.zip" 140 | noobsOSurl="ivanx.com/rasppleii/noobs-os" 141 | distDir="Raspple_II" 142 | sudo mkdir -p /tmp/p3/os/$distDir 143 | sudo sed -i 's:/Raspbian:/Raspple_II:' /tmp/p3/installed_os.json 144 | sudo wget -qO /tmp/p3/icon.png $noobsOSurl/Raspple_II.png 145 | { wget -qO- $noobsOSurl/slidesAB.tar | sudo tar -C /tmp/p3/os/$distDir -x; } &> /dev/null 146 | else 147 | echo "Downloading NOOBS lite..." 148 | noobsRoot="downloads.raspberrypi.org/NOOBS_lite/images/" 149 | noobsDir=$(wget -qO- $noobsRoot | grep '^ /dev/null 156 | fi 157 | sudo rm -rf /tmp/p3/cache 2> /dev/null 158 | releaseDate=$(wget -qO- $noobsOSurl/os.json | grep 'release_date' | cut -f 4 -d '"') 159 | sudo sed -i 's/"release_date".*$/"release_date" : "'$releaseDate'"/' /tmp/p3/installed_os.json 160 | sudo sed -i 's/keyboard_layout=gb/keyboard_layout=us/' /tmp/p3/noobs.conf 161 | sudo sed -i 's:/mnt/:/settings/:' /tmp/p3/installed_os.json 162 | sudo sed -i 's@"icon".*,@"icon" : "/settings/os/'$distDir'/icon.png",@' /tmp/p3/installed_os.json 163 | sudo cp /tmp/p3/icon.png /tmp/p3/os/$distDir 164 | sudo wget -qO /tmp/p3/os/$distDir/os.json $noobsOSurl/os.json 165 | sudo wget -qO /tmp/p3/os/$distDir/partition_setup.sh $noobsOSurl/partition_setup.sh 166 | sudo wget -qO /tmp/p3/os/$distDir/partitions.json $noobsOSurl/partitions.json 167 | sudo umount /tmp/p3 168 | rmdir /tmp/p3 169 | 170 | # update Partition 1 171 | mkdir -p /tmp/p1 172 | sudo mount /dev/mmcblk0p1 /tmp/p1 173 | wget -qO /tmp/noobs_lite.zip $noobsUrl 174 | sudo rm -rf /tmp/p1/* 175 | sudo unzip -d /tmp/p1 /tmp/noobs_lite.zip 176 | sudo sed -i 's/^runinstaller //' /tmp/p1/recovery.cmdline 177 | sudo sed -i 's/silentinstall//' /tmp/p1/recovery.cmdline 178 | grep -q 'keyboard=us' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 keyboard=us/' /tmp/p1/recovery.cmdline 179 | grep -q 'disablesafemode' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 disablesafemode/' /tmp/p1/recovery.cmdline 180 | sudo umount /tmp/p1 181 | rmdir /tmp/p1 182 | 183 | sudo sed -i 's/\(Raspple II release.*[^u]$\)/\1u/' /etc/issue 184 | fi 185 | 186 | echo 187 | echo "*** Raspbian update completed. ***" 188 | echo 189 | 190 | cd /tmp 191 | 192 | if [[ $updateA2Cloud ]]; then 193 | wget -qO /tmp/a2cloud-setup ivanx.com/a2cloud/setup/ 194 | source /tmp/a2cloud-setup -y -r noSetGroups 195 | if acmd -g /usr/share/gsport/disks/GSport\ Internet\ Starter\ Kit.2mg SYSTEM/FONTS/SIS.4.10 &> /dev/null; then 196 | wget -qO /tmp/ua2.txt ivanx.com/rasppleii/files/a/ua2.txt 197 | source /tmp/ua2.txt 198 | fi 199 | echo 200 | echo "*** A2CLOUD update completed. ***" 201 | echo 202 | fi 203 | 204 | cd /tmp 205 | 206 | if [[ $updateA2Server ]]; then 207 | wget -q -O /tmp/a2server-setup ivanx.com/a2server/setup/ 208 | if ps aux | grep -q [s]mbd; then 209 | source /tmp/a2server-setup -y -r -w 210 | else 211 | source /tmp/a2server-setup -y -r 212 | fi 213 | echo 214 | echo "*** A2SERVER update completed. ***" 215 | echo 216 | fi 217 | 218 | cd "$origDir" 219 | 220 | if [[ ! $autoYes ]]; then 221 | echo 222 | echo 223 | echo "Your system has been updated and needs to reboot to use its new software." 224 | echo 225 | echo -n "Reboot now (recommended)? " 226 | read 227 | if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then 228 | sudo shutdown -r now 229 | fi 230 | else 231 | echo "*** raspbian-update completed. ***" 232 | sudo shutdown -r now 233 | fi 234 | -------------------------------------------------------------------------------- /scripts/tools/a2server-aliases.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | alias a2server-help="more /usr/local/etc/a2server-help.txt" 5 | alias a2server-setup='wget -q -O /tmp/a2server-setup ${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/NJRoadfan/a2server/currentdev/}setup/index.txt || { echo "Can'"'"'t download A2SERVER setup scripts. Do you has internet?"; false; } && source /tmp/a2server-setup' 6 | 7 | alias a2server-version="cat /usr/local/etc/A2SERVER-version" 8 | alias a2server-update='wget -q -O /tmp/a2server-update ${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/NJRoadfan/a2server/currentdev/}update/index.txt || { echo "Can'"'"'t download A2SERVER setup scripts. Do you has internet?"; false; } && source /tmp/a2server-update' 9 | 10 | alias system-shutdown='sudo shutdown -h now' 11 | alias system-restart='sudo shutdown -r now' 12 | 13 | 14 | alias raspi-config='[[ -f /usr/bin/raspi-config ]] && sudo /usr/bin/raspi-config || echo "raspi-config not found. Are you using a Raspberry Pi with Raspbian?"' 15 | 16 | alias welcome-message-edit='sudo nano /etc/motd' 17 | 18 | alias showip='ip a show dev enp0s3 | grep "inet " | cut -dt -f2 | cut -db -f1' 19 | alias showmac='ip a show dev enp0s3 | grep "link/ether" | cut -dr -f2 | cut -db -f1' 20 | alias showip-wifi='ip a show dev wlan0 | grep "inet " | cut -dt -f2 | cut -db -f1' 21 | alias showmac-wifi='ip a show dev wlan0 | grep "link/ether" | cut -dr -f2 | cut -db -f1' 22 | 23 | alias netatalk-stop="sudo systemctl stop atalkd afpd papd timelord a2boot macipgw; bonjour-off" 24 | alias netatalk-start="sudo systemctl start atalkd afpd papd timelord a2boot macipgw &> /dev/null; bonjour-on" 25 | alias netatalk-restart="sudo systemctl restart atalkd afpd papd timelord a2boot macipgw &> /dev/null; bonjour-on" 26 | alias netatalk-off='sudo systemctl stop atalkd afpd papd timelord a2boot macipgw; sudo systemctl disable atalkd afpd papd a2boot timelord macipgw' 27 | alias netatalk-on='bonjour-on; sudo systemctl enable atalkd afpd papd a2boot timelord macipgw' 28 | 29 | alias bonjour-off="sudo mv /etc/avahi/services/afpd.service /etc/avahi/services/afpd.service_disabled &> /dev/null" 30 | alias bonjour-on="sudo mv /etc/avahi/services/afpd.service_disabled /etc/avahi/services/afpd.service &> /dev/null" 31 | 32 | 33 | #alias netatalk-router-on='sudo sed -i '"'"'s/^\([^# ]*\)\( .*\)$/\1 -router\2 -zone "A2SERVER"/'"'"' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' 34 | #alias netatalk-router-off='sudo sed -i '"'"'s/^\([^#].*\) -router\(.*\) -zone [^ ]*\(.*\)$/\1\2\3/'"'"' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' 35 | 36 | 37 | #alias netatalk-eth='sudo sed -i 's/^wlan0/enp0s3/' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' 38 | #alias netatalk-wifi='sudo sed -i 's/^enp0s3/wlan0/' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' 39 | 40 | 41 | NETATALK="/usr/local/etc/netatalk" 42 | A2FILES="/srv/A2SERVER/A2FILES" 43 | GSFILES="/srv/A2SERVER/GSFILES" 44 | 45 | alias netboot-gsos="mkatinit -gs -d -f" 46 | alias netboot-gsos-guest="mkatinit -gs -d -f guest" 47 | alias netboot-p8="mkatinit -d -f" 48 | alias netboot-p8-guest="mkatinit -d -f guest" 49 | 50 | 51 | 52 | 53 | alias guest-off="sudo sed -i 's/uams_guest.so,//' /usr/local/etc/netatalk/afpd.conf; [[ -f /etc/samba/smb.conf ]] && sudo sed -i 's/^ guest ok = yes/ guest ok = no/' /etc/samba/smb.conf; netatalk-restart" 54 | alias guest-on="sudo sed -i 's/-uamlist uams_clrtxt.so/-uamlist uams_guest.so,uams_clrtxt.so/' /usr/local/etc/netatalk/afpd.conf; [[ -f /etc/samba/smb.conf ]] && sudo sed -i 's/^ guest ok = no/ guest ok = yes/' /etc/samba/smb.conf; netatalk-restart" 55 | 56 | 57 | alias samba-off='sudo systemctl stop smbd nmbd; sudo systemctl disable smbd nmbd &> /dev/null' 58 | alias samba-on='sudo systemctl enable smbd nmbd &> /dev/null; sudo systemctl start smbd nmbd' 59 | alias samba-stop='sudo systemctl stop smbd nmbd' 60 | alias samba-start='sudo systemctl start smbd nmbd' 61 | alias samba-restart='sudo systemctl restart smbd nmbd' 62 | 63 | alias a2files-share="sudo sed -i 's/^#share2/\/srv\/A2SERVER\/A2FILES\ A2FILES options:prodos ea:ad/' /usr/local/etc/netatalk/AppleVolumes.default; [[ -d /srv/A2SERVER/A2FILES ]] || mkdir /srv/A2SERVER/A2FILES" 64 | alias a2files-unshare="sudo sed -i 's/^\/srv\/A2SERVER\/A2FILES.*$/#share2/' /usr/local/etc/netatalk/AppleVolumes.default" 65 | 66 | alias showalias="alias | cut -d= -f 1 | cut -d' ' -f2 | more" 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | # 76 | -------------------------------------------------------------------------------- /scripts/tools/a2server-help.txt: -------------------------------------------------------------------------------- 1 | A2SERVER commands: 2 | (note: new commands may be added; use a2server-setup to refresh) 3 | 4 | a2server-help: show this list of commands 5 | a2server-setup: set up network boot, Windows access, Farallon fix, 6 | refresh command list 7 | a2server-version: see installed version of A2SERVER 8 | a2server-update: check for update to A2SERVER 9 | 10 | system-shutdown: shut down the server 11 | system-restart: shut down and restart the server 12 | 13 | Raspberry Pi commands, if you're using one: 14 | raspi-config: utilize all space on RPi SD card & other options 15 | 16 | welcome-message-edit: change the welcome message 17 | 18 | showip: show the current ethernet IP address of the server 19 | showmac: show the MAC (Ethernet hardware) address of the server 20 | showip-wifi: show the current wifi IP address of the server 21 | showmac-wifi: show the MAC (wifi hardware) address of the server 22 | 23 | netatalk-stop: stop the netatalk service until reboot 24 | netatalk-start: start the netatalk service 25 | netatalk-restart: restart the netatalk service 26 | netatalk-off: disable the netatalk service (even after reboot) 27 | netatalk-on: enable the netatalk service 28 | 29 | bonjour-off: disable advertisement of shared folders to OS X 30 | bonjour-on : enable advertisement of shared folders to OS X 31 | (these are automatically set by the netatalk commands above) 32 | 33 | environment variables: 34 | $NETATALK: directory containing netatalk configuration files 35 | $A2FILES : directory containing A2FILES shared volume 36 | $GSFILES : directory containing GSFILES shared volume 37 | 38 | netboot-gsos: set the current user to netboot into GS/OS (default) 39 | netboot-gsos-guest: set guests to netboot into GS/OS 40 | netboot-p8: set the current user to netboot into ProDOS 8 41 | netboot-p8-guest: set guests to netboot into ProDOS 8 (default) 42 | note: when a IIgs is set to network boot into GS/OS, using the Network 43 | control panel or the NETBOOT.GSOS utility, guests will behave like 44 | registered users, and ignore the netboot setting of the guest user 45 | 46 | guest-off: disallow guest access to A2SERVER 47 | guest-on: allow guest access to A2SERVER (default) 48 | note: by default, Guest access is the only way to network boot into 49 | ProDOS 8. For registered user boot into ProDOS 8, type "netboot-p8" 50 | 51 | samba-off: disable Windows file sharing (even after reboot) 52 | samba-on: enable Windows file Sharing 53 | samba-stop: stop Windows file sharing until reboot 54 | samba-start: start Windows file sharing 55 | samba-restart: stop and restart Windows file sharing 56 | 57 | a2files-share: disable the A2FILES shared volume 58 | a2files-unshare: enable the A2FILES shared volume 59 | 60 | nulib2: create, extract, and work with NuFX (ShrinkIt) archive files 61 | unar: extract other archive files (multiformat) 62 | lsar: list contents of other archive files (multiformat) 63 | 64 | afptype: set the ProDOS type/auxtype or Mac OS type/creator of a file 65 | afpsync: register files introduced outside of AFP with netatalk 66 | mkatinit: set up network boot configuration files 67 | cppo: catalog and copy files from ProDOS image file (slow, but works) 68 | (add -h to show help for the above four commands, e.g. "afptype -h") 69 | -------------------------------------------------------------------------------- /scripts/tools/a2serverrc.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | export A2SERVER_SCRIPT_URL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/NJRoadfan/a2server/currentdev/}" 5 | export A2SERVER_BINARY_URL="${A2SERVER_BINARY_URL:-http://appleii.ivanx.com/a2server/files/}" 6 | source /usr/local/etc/a2server-aliases 7 | -------------------------------------------------------------------------------- /scripts/tools/afpsync.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # afpsync: updates .AppleDouble components of files on shared volumes 5 | 6 | # this must be used if any files are copied to the shared volume via 7 | # non-AFP methods (directly, via Samba, etc). 8 | 9 | # usage: 10 | # afpsync [-v] [shared volume path] 11 | # 12 | # -v will silently create a .volinfo file if none exists. 13 | # If a path is specified, only that volume is synced; otherwise, all 14 | # all paths in /srv/A2SERVER which appear in 15 | # /usr/local/etc/netatalk/AppleVolumes.default are synced. 16 | 17 | processPath () { 18 | if [[ ! -d $sharepath ]]; then 19 | echo "$sharepath does not exist." 20 | else 21 | volinfo="$sharepath/.AppleDesktop/.volinfo" 22 | if [[ ! -f $volinfo ]]; then 23 | if [[ ! $force ]]; then 24 | echo "Cannot update AppleDouble files for volume $sharepath," 25 | echo "because its .volinfo file does not exist. To create it, log" 26 | echo "into the volume from an Apple II or Mac client computer," 27 | echo "or use \"afpsync -v\"." 28 | else 29 | if (( $1 )); then 30 | mkvolinfo -f -c $sharepath 31 | else 32 | mkvolinfo -f $sharepath 33 | fi 34 | $0 $sharepath 35 | fi 36 | else 37 | IFS='' 38 | result=$(sudo dbd -r $sharepath | grep encoding) 39 | f=$(wc -l <<< $result) 40 | [[ $(wc -w <<< $result) == 0 ]] && f=0 41 | [[ $f -eq 1 && $(grep AppleDesktop <<< "$result") && $(grep MTOULOWER $sharepath/.AppleDesktop/.volinfo) ]] && (( f-- )) 42 | if (( f == 0 )); then 43 | echo "AppleDouble files have been updated for volume $sharepath." 44 | else 45 | [[ ! $renameLower ]] && echo "Could not update all files on volume $sharepath." 46 | if [[ $showerrors ]]; then 47 | echo $result \ 48 | | while read LINE; do 49 | [[ ! $(echo $LINE | grep APPLEDESKTOP) ]] && echo $LINE 50 | done 51 | elif [[ $renameLower ]]; then 52 | echo $result \ 53 | | while read LINE; do 54 | if [[ ! $(echo $LINE | grep APPLEDESKTOP) ]]; then 55 | filepath=$(echo $LINE | sed "s/^Bad\ encoding\ for\ '//" | sed s/\'//) 56 | filename=${filepath##*/} 57 | filedir=${filepath%/*} 58 | mv $filepath $filedir/${filename^^} 59 | echo "Renamed $filedir/${filename^^}." 60 | fi 61 | done 62 | $0 $sharepath 63 | else 64 | echo "Use afpsync -e to see error details." 65 | fi 66 | fi 67 | unset IFS 68 | fi 69 | fi 70 | } 71 | 72 | while [[ $1 == "-r" || $1 == "-e" || $1 = "-v" ]]; do 73 | 74 | if [[ $1 == "-v" ]]; then 75 | force=1 76 | shift 77 | fi 78 | 79 | if [[ $1 == "-e" ]]; then 80 | showerrors=1 81 | shift 82 | fi 83 | 84 | if [[ $1 == "-r" ]]; then 85 | renameLower=1 86 | shift 87 | fi 88 | 89 | done 90 | 91 | if [[ ${1:0:1} == "-" ]]; then 92 | echo "Usage: afpsync [-e|-r] [-v] [shared volume path]" 93 | echo 94 | echo "-e: show error details" 95 | echo "-r: rename lowercase filenames to uppercase" 96 | echo "-v: create .volinfo file if none exists" 97 | echo "If no directory is specified, all found in" 98 | echo " /usr/local/etc/netatalk/AppleVolumes.default are processed." 99 | echo 100 | else 101 | sudo true 102 | if [[ $1 ]]; then 103 | sharepath=$(readlink -m $1) 104 | # behavior change in 1.3.0: now defaults to mixed case 105 | # on a volume when specifying a folder and -v 106 | # (as opposed to defaulting to casefold:toupper previously) 107 | processPath 1 108 | else 109 | grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | \ 110 | while read line; do 111 | [[ $(echo $line | grep toupper) ]]; nocasefold=$? 112 | sharepath=$(echo $line | cut -d" " -f1) 113 | processPath nocasefold 114 | done 115 | fi 116 | fi 117 | -------------------------------------------------------------------------------- /scripts/tools/afptype.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # 2-25-11: tested on 10.6.5 and Ubuntu 10.10. Final. 5 | # 10-5-24: update to support netatalk 3.x EAs. 6 | 7 | # to do: allow hex offsets 8 | 9 | # These bash functions perform single-byte dec-hex-character conversions 10 | # and file read/write operations, and hopefully work identically across 11 | # different platforms. Each can operate by itself without the presence 12 | # of the others. They have been tested on Mac OS X 10.6 and 13 | # Ubuntu Linux 10.10. Your mileage may vary. 14 | 15 | # You provide parameters to the functions as arguments, or alternatively 16 | # standard in (for the functions which accept characters). Examples: 17 | # Write hex byte with value "F0" to offset 23 in file "myFile": 18 | # writecharHex myFile 23 F0 19 | # Write "ABCDE" to the beginning of file "myFile" 20 | # echo "ABCDE" | writechars myFile 21 | 22 | # For functions which output something (all but the write operations), 23 | # you can call the functions with command substitution if you want to 24 | # assign the output to a variable rather than display it. Examples: 25 | # Convert decimal value 65 to its hexadecimal equivalent: 26 | # val=$(decToHex 65) 27 | # Get decimal value of the character/byte at offset 215 in "myFile": 28 | # val=$(readcharDec "myFile" 215) 29 | 30 | # For functions which convert to or from a character, 0-127 will be 31 | # ASCII/UTF-8, while 128-255 will be system/locale/codepage dependent. 32 | # In this context, a character is effectively the same as a byte. 33 | 34 | # The functions return a non-zero exit status for invalid or missing 35 | # arguments. If you don't need these checks, remove the lines 36 | # above the comment "args are valid" (or as otherwise noted). 37 | # The exit statuses are, generally: 38 | # 0 = no error 39 | # 8 = extraneous argument 40 | # 9 = standard input is invalid 41 | # 1x = missing required argument (e.g. 11 for missing argument 1) 42 | # 2x = argument is invalid (e.g. 22 for invalid argument 2) 43 | # any other exit status will originate from the final command in the 44 | # function (e.g. dd, printf) 45 | 46 | # For the functions which output chars (readchars, decToChar, and 47 | # hexToChar), be aware that NUL (0) and trailing LF (10/0x0A) chars will 48 | # be stripped when assigned to a variable, and cannot appear in an 49 | # argument. To preserve them, pipe the output elsewhere, such as into 50 | # charToDec, charToHex, writechars, or a command. (readcharDec and 51 | # readcharHex handle these characters correctly.) 52 | 53 | # questions/comments to ivan@ivanx.com 54 | 55 | decToHex () { 56 | # converts single-byte decimal value to hexadecimal equivalent 57 | # arg: decimal value from 0-255 58 | # out: two-digit hex value from 00-FF 59 | #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg 60 | [[ $1 ]] || return 11 61 | [[ $2 ]] && return 8 62 | [[ ( $(printf %d "$1" 2> /dev/null) == $1 ) \ 63 | && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 64 | # args are valid 65 | printf %02X "$1" 66 | } 67 | 68 | hexToDec () { 69 | # converts single-byte hexadecimal value to decimal equivalent 70 | # arg: two-digit hex value from 00-FF 71 | # out: decimal value 72 | #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg 73 | [[ $1 ]] || return 11 74 | [[ $2 ]] && return 8 75 | [[ ${#1} -eq 2 ]] || return 21 76 | [[ $(printf %02X "0x$1" 2> /dev/null) == \ 77 | $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21 78 | # args are valid 79 | printf %d "0x$1" 80 | } 81 | 82 | charToDec () { 83 | # converts single character to corresponding decimal value 84 | # stdin OR arg: one character 85 | # [arg overrides stdin; stdin is required for NUL (0) or LF (0x0A)] 86 | # out: decimal value from 0-255 87 | #exit: 8=extraneous arg, 9=invalid stdin, 88 | # 11=missing stdin/arg, 21=invalid arg 89 | [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } 90 | [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } 91 | # arg/stdin is potentially valid (additional check below) 92 | charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" 93 | [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) 94 | # above line verifies that arg/stdin is valid 95 | [[ ${#charX} -ne 2 ]] && { echo -n 0; return 0; } 96 | echo -n "${charX:0:1}" | od -t u1 | \ 97 | head -1 | sed 's/[0\ ]*//' | tr -d ' \n' 98 | } 99 | 100 | charToHex () { 101 | # converts single character to corresponding hexadecimal value 102 | # stdin OR arg: one character 103 | # [arg overrides stdin; stdin is required for NUL (0) or LF (0x0A)] 104 | # out: decimal value from 0-255 105 | #exit: 8=extraneous arg, 9=invalid stdin, 106 | # 11=missing stdin/arg, 21=invalid arg 107 | [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } 108 | [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } 109 | # arg/stdin is potentially valid (additional check below) 110 | charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" 111 | [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) 112 | # above line verifies that stdin/arg is valid 113 | [[ ${#charX} -ne 2 ]] && { echo -n "00"; return 0; } 114 | printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \ 115 | head -1 | sed 's/[0\ ]*//' | tr -d ' \n') 116 | } 117 | 118 | decToChar () { 119 | # converts single-byte decimal value to equivalent character 120 | # arg: decimal number from 0-255 121 | # out: one character 122 | #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg 123 | [[ $1 ]] || return 11 124 | [[ $2 ]] && return 8 125 | [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ 126 | && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 127 | # args are valid 128 | echo -n -e "\x$(printf %02X "$1")" 129 | } 130 | 131 | hexToChar () { 132 | # converts single-byte hexadecimal value to corresponding character 133 | # arg: two-digit hexadecimal number from 00-FF 134 | # out: one character 135 | #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg 136 | [[ $1 ]] || return 11 137 | [[ $2 ]] && return 8 138 | [[ ${#1} -eq 2 ]] || return 21 139 | [[ $(printf %02X "0x$1" 2> /dev/null) == \ 140 | $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21 141 | # args are valid 142 | echo -n -e "\x$1" 143 | } 144 | 145 | readchars () { 146 | # read one or more characters from a file 147 | # arg1: filename 148 | # arg2: (optional) offset (# of bytes to skip before reading) 149 | # arg3: (optional) # of chars to read (default is until end of file) 150 | # out: sequence of characters 151 | # exit: 8=extraneous arg, 11=missing arg1, 152 | # 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 153 | [[ $1 ]] || return 11 154 | [[ $4 ]] && return 8 155 | [[ -f $1 ]] || return 21 156 | [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ 157 | && ( $2 -ge 0 ) ]] || return 22; } 158 | [[ $3 ]] && { [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \ 159 | && ( $3 -ge 0 ) ]] || return 23; } 160 | # args are valid 161 | dd if="$1" bs=1 skip=$(($2)) $([[ $3 ]] && echo -n "count=$3") \ 162 | 2> /dev/null | tr -d ' \0' 163 | } 164 | 165 | readcharDec () { 166 | # read one character from file & convert to equivalent decimal value 167 | # arg1: filename 168 | # arg2: (optional) offset (# of bytes to skip before reading) 169 | # out: decimal value from 0-255 170 | # exit: 8=extraneous arg, 11=missing arg1, 171 | # 21=invalid arg1, 22=invalid arg2 172 | [[ $1 ]] || return 11 173 | [[ $3 ]] && return 8 174 | [[ -f $1 ]] || return 21 175 | [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ 176 | && ( $2 -ge 0 ) ]] || return 22; } 177 | # args are valid 178 | charX="$(dd if="$1" bs=1 skip=$(($2)) \ 179 | count=1 2> /dev/null | tr -d '\0'; echo -n X)" 180 | [[ ${#charX} -gt 1 ]] || { echo -n 0; return 0; } 181 | echo -n "${charX:0:1}" | od -t u1 | \ 182 | head -1 | sed 's/[0\ ]*//' | tr -d ' \n' 183 | } 184 | 185 | readcharHex () { 186 | # read one character from file & convert to corresponding hex value 187 | # arg1: filename 188 | # arg2: (optional) offset (# of bytes to skip before reading) 189 | # out: two-digit hex value from 00-FF 190 | # exit: 8=extraneous arg, 11=missing arg1, 191 | # 21=invalid arg1, 22=invalid arg2 192 | [[ $1 ]] || return 11 193 | [[ $3 ]] && return 8 194 | [[ -f $1 ]] || return 21 195 | [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ 196 | && ( $2 -ge 0 ) ]] || return 22; } 197 | # args are valid 198 | charX="$(dd if="$1" bs=1 skip=$(($2)) \ 199 | count=1 2> /dev/null | tr -d '\0'; echo -n X)" 200 | [[ ${#charX} -gt 1 ]] || { echo -n "00"; return 0; } 201 | printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \ 202 | head -1 | sed 's/[0\ ]*//' | tr -d ' \n') 203 | } 204 | 205 | ### 2-15-11 above tested on OS X and Linux 206 | 207 | writechars () { 208 | # write one or more characters (bytes) to file 209 | # arg1: filename 210 | # arg2: (optional) offset (# of bytes to skip before writing) 211 | # arg3 OR stdin: sequence of characters 212 | # [stdin required if writing NUL (0) or trailing LF (0x0A) chars] 213 | # out: nothing 214 | # exit: 8=extraneous arg, 11=missing arg1, 215 | # 13=missing stdin/arg3, 22=invalid arg2 216 | [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } 217 | [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ 218 | ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } 219 | [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } 220 | [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } 221 | # args are valid 222 | if [[ -t 0 ]]; then 223 | echo -n "$3" | \ 224 | dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null 225 | else 226 | dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null 227 | fi 228 | } 229 | 230 | writecharDec () { 231 | # write corresponding character of single-byte decimal value into file 232 | # arg1: filename 233 | # arg2: offset (# of bytes to skip before writing) 234 | # arg3: decimal number from 0-255 235 | # exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2, 236 | # 13=missing arg3, 22=invalid arg2, 23=invalid arg3 237 | # out: nothing 238 | [[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13 239 | [[ $4 ]] && return 8 240 | [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ 241 | && ( $2 -ge 0 ) ]] || return 22 242 | [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \ 243 | && ( $3 -ge 0 ) && ( $3 -lt 255 ) ]] || return 23 244 | # args are valid 245 | echo -n -e "\x$(printf %02X "$3")" | \ 246 | dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null 247 | } 248 | 249 | writecharHex () { 250 | # write corresponding character of single-byte hex value into file 251 | # arg1: filename 252 | # arg2: offset (# of bytes to skip before writing) 253 | # arg3: two-digit hexadecimal number from 00-FF 254 | # out: nothing 255 | # exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2, 256 | # 13=missing arg3, 22=invalid arg2, 23=invalid arg3 257 | [[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13 258 | [[ $4 ]] && return 8 259 | [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ 260 | && ( $2 -ge 0 ) ]] || return 22 261 | [[ $(printf %02X "0x$3" 2> /dev/null) == \ 262 | $(echo -n "$3" | tr [a-z] [A-Z]) ]] || return 23 263 | # args are valid 264 | echo -n -e "\x$3" | \ 265 | dd of="$1" bs=1 seek=$2 conv=notrunc 2> /dev/null 266 | } 267 | 268 | 269 | # --- afptype is below this line 270 | 271 | isHexByte () { 272 | [[ $(printf %02X "0x$1" 2> /dev/null) == \ 273 | $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 1 274 | } 275 | 276 | # support 00 and 0A as filetype chars? 277 | 278 | debug=1 279 | ptypes="04:TXT 06:BIN B3:S16 E0:SHK F9:P16 FA:INT FC:BAS FF:SYS" 280 | 281 | quit () { 282 | if [[ $2 && $debug ]]; then 283 | echo "$1" "$2" 284 | else 285 | echo -e "Error: $1" 286 | fi 287 | exit_usage 288 | } 289 | 290 | exit_usage () { 291 | echo "Usage:" 292 | echo 293 | echo "show types: afptype filename" 294 | echo "set Mac OS: afptype [-t 'type'] [-c 'creator'] [-q] filename" 295 | echo "set ProDOS: afptype [-p type] [-a auxtype] [-q] filename" 296 | echo "Mac OS type or creator must be four characters; use \x plus" 297 | echo " two hex digits for untypeables (note: use '\xZZ' for 00)." 298 | echo "ProDOS type should be two hex digits, and auxtype should be four;" 299 | echo " type can alternatively be BAS, BIN, INT, P16, S16, SHK, SYS, TXT." 300 | echo "-q skips recheck of file (show types) after setting" 301 | echo 302 | exit 1 303 | } 304 | 305 | lookupPdosType () { 306 | # looks up ProDOS hex type from code in list 'ptypes' 307 | # arg: three-character code 308 | # out: two-digit hex value 309 | #exit: 0=type found, 1=error, 2=type not found 310 | ptypes="04:TXT 06:BIN B3:S16 E0:SHK F9:P16 FA:INT FC:BAS FF:SYS" 311 | [[ $1 ]] || quit "lookupPdosType:" "no argument supplied ($1)" 312 | [[ ${#1} -eq 3 ]] || return 1 313 | arg=$(echo -n "$1" | tr [a-z] [A-Z]) 314 | for ptype in $ptypes; do 315 | if [[ ${ptype:3:3} == $arg ]]; then 316 | echo -n "${ptype:0:2}" 317 | return 0 318 | fi 319 | done 320 | echo "$1" 321 | return 1 322 | } 323 | 324 | verifyTC () { 325 | [[ $1 ]] || return 1 326 | tcX="$(echo -e -n "$1"X)" 327 | [[ ${#tcX} -eq 5 ]] || return 1 328 | echo "$tcX" 329 | } 330 | 331 | while [[ $1 && ( "${1:0:1}" == '-' ) ]]; do 332 | if [[ $1 == "-p" ]]; then 333 | [[ $p ]] && exit_usage 334 | shift 335 | p="$1" 336 | shift 337 | continue 338 | elif [[ $1 == "-a" ]]; then 339 | [[ $a ]] && exit_usage 340 | shift 341 | a="$1" 342 | shift 343 | continue 344 | elif [[ $1 == "-t" ]]; then 345 | [[ $t ]] && exit_usage 346 | shift 347 | t="$1" 348 | shift 349 | continue 350 | elif [[ $1 == "-c" ]]; then 351 | [[ $c ]] && exit_usage 352 | shift 353 | c="$1" 354 | shift 355 | continue 356 | elif [[ $1 == "-q" ]]; then 357 | [[ $q ]] && exit_usage 358 | q=1 359 | shift 360 | continue 361 | else 362 | exit_usage 363 | break 364 | fi 365 | done 366 | 367 | if [[ ( ( $p || $a ) && ( $t || $c ) ) || ( -z $1 ) ]]; then 368 | exit_usage 369 | fi 370 | 371 | #filename="$1" 372 | #shift 373 | 374 | for filename in $@; do 375 | 376 | [[ ${#@} -gt 1 ]] && linestart="($filename) " 377 | 378 | if [[ ! -f $filename ]]; then 379 | echo "${linestart}Not found." 380 | continue 381 | fi 382 | 383 | found_ea=0 384 | found_ad=0 385 | 386 | originalname=$filename 387 | 388 | # sanity check to make sure we are in a valid netatalk volume 389 | if ad ls "$(dirname "$filename")" | grep "no volume for path" &> /dev/null; then 390 | netatalk_vol=0 391 | else 392 | netatalk_vol=1 393 | if [[ -d .AppleDouble ]]; then # is it an adv2 style volume? 394 | adv2_vol=1 395 | fi 396 | fi 397 | 398 | adname="$(dirname "$filename")/.AppleDouble/$(basename "$filename")" 399 | [[ -f $adname ]] && filename=$adname 400 | ADversion=$(readcharDec "$filename" 5) 401 | if [[ ( ( $ADversion -ne 1 ) && ( $ADversion -ne 2 ) ) \ 402 | || ( "$(readchars "$filename" 1 3)" != "$(echo -e -n "\x05\x16\x07")" ) \ 403 | || ( $(readcharDec "$filename" 0) -ne 0 ) \ 404 | || ( $(readcharDec "$filename" 4) -ne 0 ) \ 405 | || ( $(readcharDec "$filename" 6) -ne 0 ) \ 406 | || ( $(readcharDec "$filename" 7) -ne 0 ) ]]; then 407 | found_adv2=0 408 | else 409 | found_ad=1 410 | found_adv2=1 411 | fi 412 | 413 | # the dbd tool in netatalk doesn't write an EA to files in volumes without one, so 414 | # we need to test if one isn't found and generate one on the fly if needed. 415 | if getfattr -n "user.org.netatalk.Metadata" $originalname &> /dev/null; then 416 | # ea found, dump the extended attribute data to a file for processing 417 | filename="/tmp/$(basename "$originalname")tmpEA" 418 | getfattr --only-values -n "user.org.netatalk.Metadata" $originalname > $filename 2> /dev/null 419 | found_ad=1 420 | found_ea=1 421 | else # no EA found, check if we are in an EA style netatalk volume and create one if needed 422 | if [[ ( $netatalk_vol -eq 1 ) && ( $found_adv2 -eq 0) && ( $adv2_vol -eq 0 ) ]]; then 423 | ad set -l none $originalname &> /dev/null # this forces creation of an EA 424 | # check again for the existance of the EA and dump if there is one 425 | if getfattr -n "user.org.netatalk.Metadata" $originalname &> /dev/null; then 426 | filename="/tmp/$(basename "$originalname")tmpEA" 427 | getfattr --only-values -n "user.org.netatalk.Metadata" $originalname > $filename 2> /dev/null 428 | found_ad=1 429 | found_ea=1 430 | else 431 | found_ad=0 432 | fi 433 | fi 434 | fi 435 | 436 | if [[ $found_ad -eq 0 ]]; then 437 | echo "${linestart}Not an AppleDouble file." 438 | continue 439 | fi 440 | 441 | entrycount=`readcharDec "$filename" 25` 442 | 443 | entry=1 444 | offset=29 445 | 446 | while [[ $(readcharDec "$filename" $offset) -ne 9 ]]; do 447 | (( entry = entry + 1 )) 448 | if (( entry > entrycount )); then 449 | echo "${linestart}Finder Info entry not found in AppleDouble file." 450 | break 451 | fi 452 | (( offset = (entry * 12 + 29) - 12 )) 453 | done 454 | (( entry > entrycount )) && continue 455 | 456 | (( offset = offset + 3 )) 457 | (( tposHi = $(readcharDec "$filename" $offset) * 256 )) 458 | (( offset = offset + 1 )) 459 | (( tpos = $(readcharDec "$filename" $offset) + tposHi )) 460 | (( cpos = tpos + 4 )) 461 | (( ppos = tpos + 1 )) 462 | (( apos = tpos + 2 )) 463 | 464 | if [[ $p || $a || $t || $c ]]; then # set 465 | if [[ $p || $a ]]; then # set prodos filetype/auxtype 466 | if [[ $p ]]; then 467 | [[ ${#p} -eq 3 ]] && { p=$(lookupPdosType $p) || quit "Invalid ProDOS type name ($p)."; } 468 | isHexByte "$p" || quit "Invalid ProDOS file type ($p)." 469 | writecharHex "$filename" $ppos "$p" 470 | fi 471 | if [[ $a ]]; then 472 | isHexByte "${a:0:2}" && isHexByte "${a:2:2}" || quit "Invalid ProDOS aux type ($a)." 473 | writecharHex "$filename" $apos "${a:0:2}" 474 | (( apos=apos+1 )) 475 | writecharHex "$filename" $apos "${a:2:2}" 476 | fi 477 | writechars "$filename" $tpos "p" 478 | writechars "$filename" $cpos "pdos" 479 | 480 | if [[ $found_ea -eq 1 ]]; then 481 | # base64 encode the altered EA since bash can't deal with null characters 482 | b64=$( cat $filename | base64 -w 0 ) 483 | newea=$( printf "# file: $originalname\nuser.org.netatalk.Metadata=0s$b64" ) 484 | printf "$newea" | setfattr --restore - 485 | fi 486 | elif [[ $t || $c ]]; then # set macintosh filetype/creator 487 | if [[ $t ]]; then 488 | type=$(verifyTC "$t") || quit "$(echo -n "Invalid Mac file type ($t)."; [[ $t == *x* ]] && echo -n " Try quotes."; echo)" 489 | writechars "$filename" $tpos "${type:0:4}" 490 | fi 491 | if [[ $c ]]; then 492 | creator=$(verifyTC "$c") || quit "$(echo -n "Invalid Mac file creator ($c)."; [[ $c == *x* ]] && echo -n " Try quotes."; echo)" 493 | writechars "$filename" $cpos "${creator:0:4}" 494 | fi 495 | if [[ $found_ea -eq 1 ]]; then 496 | # base64 encode the altered EA since bash can't deal with null characters 497 | b64=$( cat $filename | base64 -w 0 ) 498 | newea=$( printf "# file: $originalname\nuser.org.netatalk.Metadata=0s$b64" ) 499 | printf "$newea" | setfattr --restore - 500 | fi 501 | fi 502 | [[ $q ]] || { echo -n "${linestart}File changed: "; "$0" "$originalname"; } 503 | 504 | else # show 505 | [[ $q ]] && quit "Can only use -q when changing type." 506 | 507 | type="$(readchars "$filename" $tpos 4)" 508 | creator="$(readchars "$filename" $cpos 4)" 509 | 510 | echo -n "$linestart" 511 | 512 | if [[ $creator != "pdos" || ( ( $type != "TEXT" ) \ 513 | && ( $type != "PSYS" ) && ( ${type:0:1} != "p" ) ) ]]; then 514 | if [[ $creator || $type ]]; then 515 | echo "Mac file. Type:$type Creator:$creator" 516 | else 517 | echo "This file has no Mac or ProDOS file type information." 518 | fi 519 | if [[ $found_ea -eq 1 && -f $filename ]]; then 520 | rm $filename 521 | fi 522 | continue 523 | fi 524 | 525 | if [[ $type == "TEXT" ]]; then 526 | pdosType="\$04 [TXT]" 527 | pdosAuxType='$0000' 528 | elif [[ $type == "PSYS" ]]; then 529 | pdosType="\$FF [SYS]" 530 | pdosAuxType='$0000' 531 | else 532 | (( tpos=tpos+1 )) 533 | pdosType=$(readcharHex "$filename" $tpos) 534 | for ptype in $ptypes; do 535 | if [[ "${ptype:0:2}" == "$pdosType" ]]; then 536 | pdosType="$pdosType [${ptype:3:3}]" 537 | break 538 | fi 539 | done 540 | 541 | (( tpos=tpos+1 )) 542 | auxTypeHi=$(readcharHex "$filename" $tpos) 543 | (( tpos=tpos+1 )) 544 | auxTypeLo=$(readcharHex "$filename" $tpos) 545 | pdosAuxType=$auxTypeHi$auxTypeLo 546 | fi 547 | 548 | echo "ProDOS file. Type:\$$pdosType AuxType:\$$pdosAuxType" 549 | fi 550 | if [[ $found_ea -eq 1 && -f $filename ]]; then 551 | rm $filename 552 | fi 553 | done 554 | 555 | # 7-19-11 556 | # quick ProDOS testing/fixing on Linux, needs more 557 | # Mac Type testing not done yet, nor testing on a Mac 558 | 559 | # test on lunix 560 | # test inside and outside of AD directory, and from other dirs (both cases) 561 | # finish conversion writebyte/readchar library 562 | # consider return 2 for missing parameters for subroutines 563 | -------------------------------------------------------------------------------- /scripts/tools/mkatinit.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # mkatinit by Ivan Drucker, http://appleii.ivanx.com 5 | # not licensed; please modify and redistribute as you like 6 | # 1.0b4 1-30-11 7 | 8 | # 1.1d1 -- uses bashByter. NOT TESTED. 9 | 10 | # This script creates the ATINIT file required for netbooting Apple IIe and 11 | # IIGS clients from a netatalk server. ATINIT is put in the in the 12 | # (sharename)/USERS hierarchy, or the current directory if it can't. 13 | # The user can specify the ProDOS startup system program and default prefix. 14 | # If an argument is supplied, it is used as the username and the prompt is 15 | # skipped. 16 | 17 | # The ATINIT file is not as complete as the ones generated by AppleShare 3.0, 18 | # and features such as default printer are not used. 19 | 20 | # to do 21 | # possibly require confirmation if AFPD_GUEST is not set correctly 22 | # or offer to change it 23 | 24 | # from ID-bashByter library 25 | decToChar () { 26 | # converts single-byte decimal value to equivalent character 27 | # arg: decimal number from 0-255 28 | # out: one character 29 | #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg 30 | [[ $1 ]] || return 11 31 | [[ $2 ]] && return 8 32 | [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ 33 | && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 34 | # args are valid 35 | echo -n -e "\x$(printf %02X "$1")" 36 | } 37 | 38 | writechars () { 39 | # write one or more characters (bytes) to file 40 | # arg1: filename 41 | # arg2: (optional) offset (# of bytes to skip before writing) 42 | # arg3 OR stdin: sequence of characters 43 | # [stdin required if writing NUL (0) or trailing LF (0x0A) chars] 44 | # out: nothing 45 | # exit: 8=extraneous arg, 11=missing arg1, 46 | # 13=missing stdin/arg3, 22=invalid arg2 47 | [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } 48 | [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ 49 | ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } 50 | [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } 51 | [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } 52 | # args are valid 53 | if [[ -t 0 ]]; then 54 | echo -n "$3" | \ 55 | dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null 56 | else 57 | dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null 58 | fi 59 | } 60 | 61 | #---- mkatinit starts here 62 | IFS='' 63 | 64 | #defaults 65 | sharepath=$(grep options:prodos /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) 66 | prefix=/$(grep options:prodos /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f2) 67 | gsprefix=$prefix 68 | startprog="$prefix/BASIC.SYSTEM" 69 | gsstartprog="$prefix/SYSTEM/FINDER" 70 | filename="ATINIT" 71 | user=$(whoami) 72 | 73 | if [[ ! -f /usr/local/bin/afpsync ]]; then 74 | echo "ERROR: You need the \"afpsync\" program to run mkatinit!" 75 | echo "Please re-run A2SERVER setup to ensure that all user tools are installed." 76 | exit 1 77 | fi 78 | 79 | if [[ ! -f /usr/local/bin/afptype ]]; then 80 | echo "ERROR: You need the \"afptype\" program to run mkatinit!" 81 | echo "Please re-run A2SERVER setup to ensure that all user tools are installed." 82 | exit 1 83 | fi 84 | 85 | echo 86 | 87 | usersfolder=1 88 | while [ -n "$1" ] && [ "${1:0:1}" = '-' ]; do 89 | flag="$1" 90 | if [ $flag = "-gs" ]; then 91 | gs=1 92 | shift 93 | continue 94 | elif [ $flag = "-d" ]; then 95 | noprompt=1 96 | shift 97 | continue 98 | elif [ $flag = "-f" ]; then 99 | overwrite=1 100 | shift 101 | continue 102 | elif [ $flag = "-g" ]; then 103 | alsoguest=1 104 | shift 105 | continue 106 | elif [ $flag = "-c" ]; then 107 | usersfolder=0 108 | shift 109 | continue 110 | else 111 | badflag=1 112 | break 113 | fi 114 | done 115 | 116 | if [ $usersfolder -eq 0 ] && [ -n "$alsoguest" ]; then 117 | badflag=1 118 | fi 119 | 120 | if [ $badflag ]; then 121 | echo "usage: mkatinit [-gs] [-d] [-f] [-g | -c] [|guest]" 122 | echo 123 | echo " should be the name of a netatalk user, or 'guest'" 124 | echo "-gs sets the default ProDOS netboot system startup program and" 125 | echo " prefix for GS/OS (if omitted, ProDOS 8 defaults are used)" 126 | echo "-d use the default start program and prefix, without prompting" 127 | echo "-f overwrite existing ATINIT file if present, without warning" 128 | echo "-g create an ATINIT file for Guest as well as the specified user" 129 | echo "-c write ATNIT to current directory instead of USERS hierarchy" 130 | echo 131 | exit 132 | fi 133 | 134 | arg="$1" 135 | 136 | [[ -z $arg ]] && arg=$user 137 | 138 | while : ; do 139 | 140 | if [ ${#arg} -gt 32 ]; then 141 | echo "User name is too long. Exiting with no action." 142 | exit 143 | elif [ -n "$arg" ]; then 144 | if [ `echo $arg | tr '[:upper:]' '[:lower:]'` = "guest" ]; then 145 | username='' 146 | alsoguest= 147 | if [[ ! $(grep -F -s $(ls -1 /home) /etc/default/netatalk) ]]; then 148 | echo 'Warning: The AFPD_GUEST setting in /etc/default/netatalk is not assigned to a' 149 | echo 'user with a folder in /home. Guest users may be able to boot over the network' 150 | echo 'into ProDOS 8 for read-only access, but will not be able to boot into GS/OS.' 151 | if [ $gs ]; then 152 | echo ' Using ProDOS 8 defaults.' 153 | gs= 154 | else 155 | echo 156 | fi 157 | echo 158 | fi 159 | else 160 | username="$arg" 161 | if [[ ! $(ls -1 /home | grep -F -s $username) ]]; then 162 | echo "Warning: This username ($username) does not have a folder in /home. This user may" 163 | echo "not be able to boot over the network into ProDOS 8 or GS/OS." 164 | echo 165 | fi 166 | fi 167 | if [ $gs ]; then 168 | startprog="$gsstartprog" 169 | prefix="$gsprefix" 170 | fi 171 | fi 172 | 173 | # make username all caps 174 | username=`echo $username | tr '[:lower:]' '[:upper:]'` 175 | 176 | # prompt for folders 177 | if [ ! $doalsoguest ] && [ ! $noprompt ]; then 178 | while : ; do 179 | echo "Enter the ProDOS path to the startup system program." 180 | echo "default (CR to accept): $startprog" 181 | read 182 | if [ ${#REPLY} -gt 64 ]; then 183 | continue 184 | elif [ -n "$REPLY" ]; then 185 | startprog="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" 186 | echo 187 | fi 188 | break 189 | done 190 | 191 | while : ; do 192 | echo "Enter the initial ProDOS prefix:" 193 | echo "default (CR to accept): $prefix" 194 | read 195 | if [ ${#REPLY} -gt 64 ]; then 196 | continue 197 | elif [ -n "$REPLY" ]; then 198 | prefix="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" 199 | echo 200 | fi 201 | break 202 | done 203 | fi 204 | 205 | # create folders if needed 206 | filepath="$PWD/$filename" 207 | 208 | while [ $usersfolder -eq 1 ]; do 209 | # create folders for ATINIT 210 | while [ ! -d "$sharepath" ]; do 211 | echo "Shared volume '$sharepath' not found. Edit mkatinit to change the default." 212 | echo "Enter the local path to the netatalk shared volume used for netboot:" 213 | read sharepath 214 | done 215 | 216 | if [ ! -d "$sharepath/USERS" ]; then 217 | mkdir "$sharepath/USERS" 218 | if [ $? -ne 0 ]; then 219 | break 220 | fi 221 | fi 222 | if [ ! -d "$sharepath/USERS/$username" ]; then 223 | mkdir "$sharepath/USERS/$username" 224 | if [ $? -ne 0 ]; then 225 | break 226 | fi 227 | fi 228 | if [ ! -d "$sharepath/USERS/$username/SETUP" ]; then 229 | mkdir "$sharepath/USERS/$username/SETUP" 230 | if [ $? -ne 0 ]; then 231 | break 232 | fi 233 | else 234 | if [ ! -w "$sharepath/USERS/$username/SETUP" ]; then 235 | break 236 | fi 237 | fi 238 | 239 | # we have a valid USERS folder target for ATINIT 240 | filepath="$sharepath/USERS/$username/SETUP/$filename" 241 | usersfolder=2 242 | done 243 | 244 | if [ $usersfolder -eq 1 ]; then 245 | echo "Could not write to shared volume. Creating ATINIT in current directory." 246 | if [ -n "$alsoguest" ]; then 247 | echo "ATINIT for Guest user will not be created." 248 | fi 249 | echo 250 | alsoguest= 251 | fi 252 | 253 | if [ ! $doalsoguest ]; then 254 | echo "netboot start program: $startprog" 255 | echo "netboot start prefix : $prefix" 256 | echo 257 | fi 258 | 259 | #remove ATINIT if present 260 | if [ ! $overwrite ] && [ -f "$filepath" ]; then 261 | echo -n "$filepath already exists. Overwrite? " 262 | while read -s -n 1 > /dev/null 2>&1; do 263 | if [ -z "$REPLY" ]; then 264 | continue 265 | elif [ "$REPLY" = "Y" ] || [ "$REPLY" = "y" ]; then 266 | echo 267 | break 268 | elif [ "$REPLY" = "N" ] || [ "$REPLY" = "n" ]; then 269 | echo 270 | echo "Exiting with no action." 271 | exit 272 | fi 273 | done 274 | fi 275 | 276 | #write the file. start with zeroes 277 | dd if=/dev/zero of="$filepath" bs=1 count=276 2> /dev/null 278 | #put in startprog, prefix, username (first byte of each field is length) 279 | # ( echo -n "${#startprog}" | awk '{printf("%c",$0);}'; echo -n "$startprog"; ) | dd of="$filepath" bs=1 seek=7 conv=notrunc 2> /dev/null 280 | # ( echo -n "${#prefix}" | awk '{printf("%c",$0);}'; echo -n "$prefix"; ) | dd of="$filepath" bs=1 seek=78 conv=notrunc 2> /dev/null 281 | # ( echo -n "${#username}" | awk '{printf("%c",$0);}'; echo -n "$username"; ) | dd of="$filepath" bs=1 seek=143 conv=notrunc 2> /dev/null 282 | ( decToChar "${#startprog}"; echo -n "$startprog"; ) | writechars "$filepath" 7 283 | ( decToChar "${#prefix}"; echo -n "$prefix"; ) | writechars "$filepath" 78 284 | ( decToChar "${#username}"; echo -n "$username"; ) | writechars "$filepath" 143 285 | 286 | echo "Created $filepath" 287 | 288 | #add the correct ProDOS filetype to the newly created file 289 | cd "$sharepath/USERS/$username/SETUP" 290 | afpsync $sharepath > /dev/null 291 | afptype -p E2 -a 2020 -q ATINIT 292 | 293 | if [ ! $alsoguest ]; then 294 | break 295 | fi 296 | 297 | if [ $usersfolder -eq 2 ]; then 298 | usersfolder=1 299 | fi 300 | doalsoguest=1 301 | arg='guest' 302 | done 303 | 304 | echo 305 | -------------------------------------------------------------------------------- /scripts/tools/mkvolinfo.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # mkvolinfo -- creates a (share)/.AppleDesktop/.volinfo file 5 | 6 | makeVolInfoFile () { 7 | [[ -d $sharepath/.AppleDesktop ]] || mkdir $sharepath/.AppleDesktop 8 | touch $volinfo 9 | echo 'MAC_CHARSET:MAC_ROMAN' >> $volinfo 10 | echo 'VOL_CHARSET:UTF8' >> $volinfo 11 | echo 'ADOUBLE_VER:v2' >> $volinfo 12 | echo 'CNIDBACKEND:dbd' >> $volinfo 13 | echo 'CNIDDBDHOST:localhost' >> $volinfo 14 | echo 'CNIDDBDPORT:4700' >> $volinfo 15 | echo "CNID_DBPATH:$sharepath" >> $volinfo 16 | echo 'VOLUME_OPTS:PRODOS CACHEID' >> $volinfo 17 | if (( $mixedcase )); then 18 | echo 'VOLCASEFOLD:' >> $volinfo 19 | else 20 | echo 'VOLCASEFOLD:MTOULOWER UTOMUPPER' >> $volinfo 21 | fi 22 | echo 'EXTATTRTYPE:AFPVOL_EA_AD' >> $volinfo 23 | echo ".volinfo for $sharepath has been created." 24 | } 25 | 26 | while [[ $1 == "-f" || $1 == "-c" ]]; do 27 | if [[ $1 == "-f" ]]; then 28 | force=1 29 | shift 30 | fi 31 | 32 | if [[ $1 == "-c" ]]; then 33 | mixedcase=1 34 | shift 35 | fi 36 | done 37 | 38 | if [[ ${1:0:1} == "-" ]]; then 39 | 40 | echo "usage: mkvolinfo [-f] [-c] [shared volume path]" 41 | echo 42 | echo "-c will create the .volinfo file to specify no uppercase filename conversion" 43 | echo "-f will create the .volinfo file without prompting, if none exists" 44 | echo "If a path is specified, that is what is used, otherwise the last entry" 45 | echo "in /usr/local/etc/netatalk/AppleVolumes.default is used." 46 | 47 | else 48 | sudo true 49 | if [[ $1 ]]; then 50 | sharepath=$(readlink -m $1) 51 | else 52 | sharepath=$(grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) 53 | fi 54 | 55 | volinfo=$sharepath/.AppleDesktop/.volinfo 56 | 57 | if [[ ! -d $sharepath ]]; then 58 | echo "$sharepath does not exist." 59 | else 60 | if [[ -f $volinfo ]]; then 61 | echo "$volinfo already exists." 62 | else 63 | if [[ $force ]]; then 64 | makeVolInfoFile 65 | else 66 | echo "The .volinfo file is automatically generated when you first" 67 | echo "log in from an AFP (Apple II or Mac) client machine." 68 | echo "If you can't do this, you can create a .volinfo file now" 69 | echo "based on assumed defaults; proceed with caution if you have" 70 | echo "customized your AppleVolumes files." 71 | echo 72 | echo "If the path shown below is incorrect, you can specify" 73 | echo "the path to your shared volume as an argument to mkvolinfo." 74 | echo 75 | echo -n "Make .volinfo for shared volume $sharepath now? " 76 | read 77 | if [[ ${REPLY:0:1} == "y" ]] || [[ ${REPLY:0:1} == "Y" ]]; then 78 | makeVolInfoFile 79 | fi 80 | fi 81 | fi 82 | fi 83 | fi 84 | -------------------------------------------------------------------------------- /scripts/tools/netatalk-maketar.txt: -------------------------------------------------------------------------------- 1 | tar Pzcvf netatalk224-debian_x64_wheezy.tgz /etc/default/netatalk /etc/init.d/netatalk /etc/netatalk /usr/local/bin/ad /usr/local/bin/add_netatalk_printer /usr/local/bin/adv1tov2 /usr/local/bin/aecho /usr/local/bin/afpldaptest /usr/local/bin/afppasswd /usr/local/bin/apple_dump /usr/local/bin/asip-status.pl /usr/local/bin/binheader /usr/local/bin/cnid2_create /usr/local/bin/dbd /usr/local/bin/getzones /usr/local/bin/hqx2bin /usr/local/bin/lp2pap.sh /usr/local/bin/macbinary /usr/local/bin/macusers /usr/local/bin/megatron /usr/local/bin/nadheader /usr/local/bin/nbplkup /usr/local/bin/nbprgstr /usr/local/bin/nbpunrgstr /usr/local/bin/netatalk-config /usr/local/bin/pap /usr/local/bin/papstatus /usr/local/bin/psorder /usr/local/bin/showppd /usr/local/bin/single2bin /usr/local/bin/unbin /usr/local/bin/unhex /usr/local/bin/uniconv /usr/local/bin/unsingle /usr/local/etc/netatalk/afpd.conf /usr/local/etc/netatalk/AppleVolumes.default /usr/local/etc/netatalk/AppleVolumes.system /usr/local/etc/netatalk/atalkd.conf /usr/local/etc/netatalk/papd.conf /usr/local/etc/netatalk/uams/uams_clrtxt.so /usr/local/etc/netatalk/uams/uams_dhx_passwd.a /usr/local/etc/netatalk/uams/uams_dhx_passwd.la /usr/local/etc/netatalk/uams/uams_dhx_passwd.so /usr/local/etc/netatalk/uams/uams_dhx.so /usr/local/etc/netatalk/uams/uams_dhx2_passwd.a /usr/local/etc/netatalk/uams/uams_dhx2_passwd.la /usr/local/etc/netatalk/uams/uams_dhx2_passwd.so /usr/local/etc/netatalk/uams/uams_dhx2.so /usr/local/etc/netatalk/uams/uams_guest.a /usr/local/etc/netatalk/uams/uams_guest.la /usr/local/etc/netatalk/uams/uams_guest.so /usr/local/etc/netatalk/uams/uams_passwd.a /usr/local/etc/netatalk/uams/uams_passwd.la /usr/local/etc/netatalk/uams/uams_passwd.so /usr/local/etc/netatalk/uams/uams_randnum.a /usr/local/etc/netatalk/uams/uams_randnum.la /usr/local/etc/netatalk/uams/uams_randnum.so /usr/local/include/atalk/acl.h /usr/local/include/atalk/adouble.h /usr/local/include/atalk/aep.h /usr/local/include/atalk/afp.h /usr/local/include/atalk/asp.h /usr/local/include/atalk/atp.h /usr/local/include/atalk/cnid.h /usr/local/include/atalk/compat.h /usr/local/include/atalk/ddp.h /usr/local/include/atalk/directory.h /usr/local/include/atalk/dsi.h /usr/local/include/atalk/ea.h /usr/local/include/atalk/hash.h /usr/local/include/atalk/ldapconfig.h /usr/local/include/atalk/list.h /usr/local/include/atalk/logger.h /usr/local/include/atalk/nbp.h /usr/local/include/atalk/netddp.h /usr/local/include/atalk/pap.h /usr/local/include/atalk/paths.h /usr/local/include/atalk/queue.h /usr/local/include/atalk/rtmp.h /usr/local/include/atalk/server_child.h /usr/local/include/atalk/server_ipc.h /usr/local/include/atalk/tdb.h /usr/local/include/atalk/uam.h /usr/local/include/atalk/unicode.h /usr/local/include/atalk/unix.h /usr/local/include/atalk/util.h /usr/local/include/atalk/uuid.h /usr/local/include/atalk/vfs.h /usr/local/include/atalk/volinfo.h /usr/local/include/atalk/volume.h /usr/local/include/atalk/zip.h /usr/local/include/netatalk/aarp.h /usr/local/include/netatalk/at_var.h /usr/local/include/netatalk/at.h /usr/local/include/netatalk/ddp_var.h /usr/local/include/netatalk/ddp.h /usr/local/include/netatalk/endian.h /usr/local/include/netatalk/phase2.h /usr/local/lib/libatalk.a /usr/local/lib/libatalk.la /usr/local/libexec/etc2ps.sh /usr/local/libexec/ifmpap /usr/local/libexec/ifmpaprev /usr/local/libexec/ifpap /usr/local/libexec/ifpaprev /usr/local/libexec/ifwmpap /usr/local/libexec/ifwmpaprev /usr/local/libexec/ifwpap /usr/local/libexec/ifwpaprev /usr/local/libexec/ofmpap /usr/local/libexec/ofpap /usr/local/libexec/ofwmpap /usr/local/libexec/ofwpap /usr/local/libexec/psa /usr/local/libexec/psf /usr/local/libexec/tfmpap /usr/local/libexec/tfmpaprev /usr/local/libexec/tfpap /usr/local/libexec/tfpaprev /usr/local/libexec/tfwmpap /usr/local/libexec/tfwmpaprev /usr/local/libexec/tfwpap /usr/local/libexec/tfwpaprev /usr/local/sbin/a2boot /usr/local/sbin/afpd /usr/local/sbin/atalkd /usr/local/sbin/cnid_dbd /usr/local/sbin/cnid_metad /usr/local/sbin/papd /usr/local/share/aclocal/netatalk.m4 /usr/local/share/man/man1/ad.1 /usr/local/share/man/man1/aecho.1 /usr/local/share/man/man1/afpldaptest.1 /usr/local/share/man/man1/afppasswd.1 /usr/local/share/man/man1/apple_dump.1 /usr/local/share/man/man1/asip-status.pl.1 /usr/local/share/man/man1/dbd.1 /usr/local/share/man/man1/getzones.1 /usr/local/share/man/man1/hqx2bin.1 /usr/local/share/man/man1/macbinary.1 /usr/local/share/man/man1/macusers.1 /usr/local/share/man/man1/megatron.1 /usr/local/share/man/man1/nbp.1 /usr/local/share/man/man1/nbplkup.1 /usr/local/share/man/man1/nbprgstr.1 /usr/local/share/man/man1/nbpunrgstr.1 /usr/local/share/man/man1/netatalk-config.1 /usr/local/share/man/man1/pap.1 /usr/local/share/man/man1/papstatus.1 /usr/local/share/man/man1/psorder.1 /usr/local/share/man/man1/single2bin.1 /usr/local/share/man/man1/unbin.1 /usr/local/share/man/man1/unhex.1 /usr/local/share/man/man1/uniconv.1 /usr/local/share/man/man1/unsingle.1 /usr/local/share/man/man3/atalk_aton.3 /usr/local/share/man/man3/nbp_name.3 /usr/local/share/man/man4/atalk.4 /usr/local/share/man/man5/afp_ldap.conf.5 /usr/local/share/man/man5/afp_signature.conf.5 /usr/local/share/man/man5/afp_voluuid.conf.5 /usr/local/share/man/man5/afpd.conf.5 /usr/local/share/man/man5/AppleVolumes.5 /usr/local/share/man/man5/AppleVolumes.default.5 /usr/local/share/man/man5/AppleVolumes.system.5 /usr/local/share/man/man5/atalkd.conf.5 /usr/local/share/man/man5/netatalk.conf.5 /usr/local/share/man/man5/papd.conf.5 /usr/local/share/man/man8/afpd.8 /usr/local/share/man/man8/atalkd.8 /usr/local/share/man/man8/cnid_dbd.8 /usr/local/share/man/man8/cnid_metad.8 /usr/local/share/man/man8/papd.8 /usr/local/share/man/man8/papstatus.8 /usr/local/share/man/man8/psf.8 /usr/local/share/man/man8/timelord.8 /usr/local/share/netatalk/pagecount.ps /usr/local/etc/netatalk/netatalk.conf -------------------------------------------------------------------------------- /setup/index.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # A2SERVER master setup script, last update 08-Oct-24 5 | # it downloads and executes several scripts related to the setup of 6 | # netatalk configured for Apple II use on Debian or Raspbian. 7 | # more info is at http://ivanx.com/a2server 8 | 9 | # to download and execute, type: 10 | # wget ivanx.com/a2server/setup; source setup 11 | 12 | a2serverVersion="199" 13 | 14 | # Ensure URL we'll use ends in a / 15 | case "$A2SERVER_SCRIPT_URL" in 16 | */) scriptURL="$A2SERVER_SCRIPT_URL" ;; 17 | *) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/NJRoadfan/a2server/currentdev}/" ;; 18 | esac 19 | case "$A2SERVER_BINARY_URL" in 20 | */) binaryURL="$A2SERVER_BINARY_URL" ;; 21 | *) binaryURL="${A2SERVER_BINARY_URL:-https://appleii.ivanx.com/a2server/files}/" ;; 22 | esac 23 | useExternalURL=1 24 | [[ $A2SERVER_NO_EXTERNAL ]] && useExternalURL= 25 | 26 | isRpi= 27 | [[ -f /usr/bin/raspi-config ]] && isRpi=1 28 | 29 | isDebian= 30 | 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 31 | 32 | installedVersion= 33 | if [ -f /usr/local/etc/A2SERVER-version ]; then 34 | installedVersion="$(cat /usr/local/etc/A2SERVER-version)" 35 | fi 36 | echo "A2SERVER version available: $a2serverVersion" 37 | echo "A2SERVER version installed: ${installedVersion:=None}" 38 | 39 | echo 40 | [[ $scriptURL != *"ivanx.com"* && $scriptURL != *"raw.githubusercontent.com/NJRoadfan/a2server"* ]] && echo "Using script URL: $scriptURL" 41 | [[ $binaryURL != *"ivanx.com"* ]] && echo "Using binary URL: $binaryURL" 42 | [[ ! $useExternalURL ]] && echo -e "Not using external URLs. Downloads must be available from:\n ${binaryURL}external/appleii/\n ${binaryURL}external/source/\n (See the A2SERVER developer page for more information.)" 43 | 44 | skipRepoUpdate= 45 | autoAnswerYes= 46 | installAll= 47 | setupNetBoot= 48 | setupWindowsSharing= 49 | compileAlways= 50 | rm /tmp/a2server-* 2> /dev/null 51 | while [[ $1 ]]; do 52 | if [[ $1 == "-r" ]]; then 53 | shift 54 | skipRepoUpdate="-r" 55 | touch /tmp/a2server-packageReposUpdated 56 | elif [[ $1 == "-i" ]]; then 57 | shift 58 | installAll="-i" 59 | elif [[ $1 == "-y" ]]; then 60 | shift 61 | autoAnswerYes="-y" 62 | touch /tmp/a2server-autoAnswerYes 63 | elif [[ $1 == "-b" ]]; then 64 | shift 65 | setupNetBoot="-b" 66 | touch /tmp/a2server-setupNetBoot 67 | elif [[ $1 == "-h" ]]; then 68 | shift 69 | setupTashtalk="-h" 70 | touch /tmp/a2server-setupTashtalk 71 | elif [[ $1 == "-w" ]]; then 72 | shift 73 | setupWindowsSharing="-w" 74 | touch /tmp/a2server-setupWindowsSharing 75 | elif [[ $1 == "-c" ]]; then 76 | shift 77 | compileAlways="-c" 78 | touch /tmp/a2server-compileAlways 79 | elif [[ $1 == "-t" ]]; then 80 | shift 81 | multiThreadedCompilation="-t" 82 | touch /tmp/a2server-multiThreadedCompilation 83 | elif [[ $1 == "-l" ]]; then 84 | shift 85 | localScripts="-l" 86 | touch /tmp/a2server-localScripts 87 | elif [[ $1 == "-v" ]]; then 88 | shift 89 | # Version was already printed 90 | [[ $0 == "-bash" ]] && return 1 || exit 1 91 | elif [[ $1 ]]; then 92 | echo "options:" 93 | echo "-v: display installed and available versions, then exit" 94 | echo "-i: reinstall A2SERVER software (but not Apple II software)" 95 | echo "-y: auto-answer yes to all prompts" 96 | echo "-r: don't update package repositories" 97 | echo "-b: auto-setup network boot (use with -y)" 98 | echo "-h: auto-setup TashTalk Hat on RPi (use with -y)" 99 | echo "-w: auto-setup Windows file sharing (use with -y)" 100 | echo "-c: compile non-package items, rather than downloading binaries" 101 | echo "-t: use all available CPU cores for multi threaded compilation" 102 | echo "-l: use local scripts, rather than downloading from remote server" 103 | [[ $0 == "-bash" ]] && return 1 || exit 1 104 | fi 105 | done 106 | 107 | if { [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) < 200 )); }; then 108 | echo 109 | echo "WARNING: The current A2SERVER installer scripts haven't been tested for" 110 | echo "updating the earlier version of A2SERVER that you have. A fresh install" 111 | echo "is suggested. Continuing is not recommended and could make A2SERVER" 112 | echo "no longer work properly, or cause data to be lost." 113 | fi 114 | 115 | a2server_update=0 116 | doSetup=1 117 | 118 | if { [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) < 152 )); }; then 119 | a2server_update=1 120 | fi 121 | 122 | unsupportedOS=1 123 | touch /tmp/a2server-compileAlways 124 | 125 | if [[ $isDebian ]]; then # supported Debian? 126 | debianVersion=$(cat /etc/debian_version) 127 | debianSupported="-12.7- -11.11-" 128 | [[ $debianSupported == *-$debianVersion-* ]] && unsupportedOS= 129 | fi 130 | 131 | if [[ $unsupportedOS && $isDebian ]]; then 132 | echo 133 | echo "A2SERVER and its installer scripts have been tested on Debian 10/11/12," 134 | echo "though not this specific point release ($debianVersion). Just FYI." 135 | unsupportedOS= 136 | fi 137 | 138 | if [[ $unsupportedOS ]]; then 139 | echo 140 | echo "WARNING: A2SERVER and its installer scripts have only been tested on" 141 | echo "Debian and RPi OS. Continuing is probably fine, but might not be." 142 | echo "Theoretical worst case would be your operating system no longer works" 143 | echo "properly or data is lost, so consider backing up first." 144 | fi 145 | 146 | doSetup=1 147 | if [[ $installAll || ! -f /usr/local/etc/a2server-help.txt ]] || (( $a2server_update )); then 148 | echo 149 | echo "Setting up A2SERVER will take up to 60 minutes, during which" 150 | echo "you'll see a bunch of stuff spit out across the screen." 151 | echo 152 | if [[ ! $autoAnswerYes ]]; then 153 | echo -n "Ready to set up A2SERVER? " 154 | read 155 | [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; doSetup=$(( 1 - $? )) 156 | fi 157 | fi 158 | 159 | if (( $doSetup )); then 160 | 161 | echo 162 | echo "a2server-setup modifies files and performs actions as the root user." 163 | echo "For details, visit http://ivanx.com/a2server." 164 | echo 165 | if [[ ! $autoAnswerYes ]]; then 166 | echo -n "Continue? " 167 | read 168 | [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; doSetup=$(( 1 - $? )) 169 | fi 170 | 171 | if (( $doSetup )); then 172 | 173 | if [[ -f /tmp/a2server-localScripts ]]; then 174 | echo "A2SERVER: Copying local scripts..." 175 | baseDir=$(dirname "$(readlink -f "${0}")") 176 | localScriptDir="$baseDir/../scripts" 177 | cp "$localScriptDir/a2server-1-storage.txt" /tmp/1.storage || exit 1 178 | cp "$localScriptDir/a2server-2-tools.txt" /tmp/2.tools || exit 1 179 | cp "$localScriptDir/a2server-3-sharing.txt" /tmp/3.sharing || exit 1 180 | cp "$localScriptDir/a2server-5-netboot.txt" /tmp/5.netboot || exit 1 181 | cp "$localScriptDir/a2server-6-samba.txt" /tmp/6.samba || exit 1 182 | cp "$localScriptDir/a2server-7-console.txt" /tmp/7.console || exit 1 183 | else 184 | echo "A2SERVER: Downloading scripts..." 185 | wget -q -O /tmp/1.storage "${scriptURL}scripts/a2server-1-storage.txt" 186 | wget -q -O /tmp/2.tools "${scriptURL}scripts/a2server-2-tools.txt" 187 | wget -q -O /tmp/3.sharing "${scriptURL}scripts/a2server-3-sharing.txt" 188 | wget -q -O /tmp/5.netboot "${scriptURL}scripts/a2server-5-netboot.txt" 189 | wget -q -O /tmp/6.samba "${scriptURL}scripts/a2server-6-samba.txt" 190 | wget -q -O /tmp/7.console "${scriptURL}scripts/a2server-7-console.txt" 191 | fi 192 | chmod ugo+x /tmp/1.storage /tmp/2.tools /tmp/3.sharing /tmp/5.netboot /tmp/6.samba /tmp/7.console 193 | 194 | echo "A2SERVER: Scripts have been prepared. Installing..." 195 | 196 | if [[ $installAll ]]; then 197 | sudo rm /usr/local/etc/A2SERVER-version 2> /dev/null 198 | sudo rm /usr/local/bin/nulib2 2> /dev/null 199 | sudo rm /usr/local/bin/unar 2> /dev/null 200 | sudo rm /usr/local/sbin/macipgw 2> /dev/null 201 | sudo rm /usr/local/bin/ciopfs 2> /dev/null 202 | sudo rm /usr/local/etc/netatalk/afppasswd 2> /dev/null 203 | sudo rm /usr/local/etc/netatalk/a2boot/p8 /usr/local/etc/netatalk/a2boot/ProDOS16\ Image 2> /dev/null 204 | fi 205 | 206 | /tmp/1.storage 207 | rm /tmp/1.storage 208 | /tmp/2.tools 209 | rm /tmp/2.tools 210 | /tmp/3.sharing 211 | rm /tmp/3.sharing 212 | /tmp/5.netboot 213 | rm /tmp/5.netboot 214 | /tmp/6.samba 215 | rm /tmp/6.samba 216 | /tmp/7.console 217 | rm /tmp/7.console 218 | rm /tmp/a2server-packageReposUpdated &> /dev/null 219 | 220 | if [[ ! -f /usr/local/etc/A2SERVER-version ]] \ 221 | || (( $(head -c 3 /usr/local/etc/A2SERVER-version) < ${a2serverVersion:0:3} )); then 222 | echo "$a2serverVersion" | sudo tee /usr/local/etc/A2SERVER-version &> /dev/null 223 | fi 224 | 225 | source /usr/local/etc/a2serverrc 226 | 227 | # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) 228 | kernelRelease=$(uname -r) 229 | kernelMajorRelease=$(cut -d '.' -f 1 <<< $kernelRelease) 230 | kernelMinorRelease=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') 231 | 232 | echo 233 | # all done, see if AppleTalk is available and notify either way 234 | if [[ $(ps aux | grep [a]talkd) ]]; then 235 | echo "You now have a fully functional file server for Apple II clients." 236 | echo "On an Apple IIe, it should be accessible via \"Log In\" on the" 237 | echo "Workstation Card software. For IIgs users, it should be accessible" 238 | echo "via the AppleShare control panel." 239 | if [[ -f /srv/A2SERVER/A2FILES/System/Start.GS.OS ]]; then 240 | echo 241 | echo "You can network boot GS/OS." 242 | echo "On a ROM 01 IIgs, set slot 1 (printer port), or slot 2 (modem port)" 243 | echo "to Your Card, and slot 7 to AppleTalk, and Startup Slot to 7 or Scan." 244 | echo "On a ROM 3 IIgs, set slot 1 or 2, and Startup Slot, to AppleTalk." 245 | fi 246 | if [[ -f /srv/A2SERVER/A2FILES/BASIC.System ]]; then 247 | echo 248 | echo "You can network boot ProDOS 8. On an Apple IIe, put your Workstation Card" 249 | echo "in a slot above your disk controller card, or type PR#X with open-apple" 250 | echo "held down, with X being the slot of your Workstation Card." 251 | echo 'On a IIgs, press "8" during the initial procession of periods.' 252 | fi 253 | echo 254 | echo "A2SERVER setup is complete! Go connect from your Apple II!" 255 | echo 256 | else 257 | echo "A2SERVER is now configured, but Apple II clients cannot connect because" 258 | echo "AppleTalk networking is unavailable. Please make sure that" 259 | echo "your Linux distribution has a loadable AppleTalk kernel module or" 260 | echo "has AppleTalk built into the kernel, and restart your server." 261 | echo "Or, if you previously disabled AppleTalk in A2SERVER, re-enable it" 262 | echo "by typing 'appletalk-on'." 263 | echo 264 | fi 265 | if [[ -f /tmp/rpiUpdate ]]; then 266 | echo "A2SERVER is now configured, but Apple II clients will not be able" 267 | echo "to connect via your TashTalk Hat or LToUDP until you restart your Raspberry Pi." 268 | echo 269 | if [[ ! $autoAnswerYes ]]; then 270 | echo -n "Restart now? " 271 | read 272 | fi 273 | if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then 274 | sudo shutdown -r now 275 | echo 276 | echo "A2SERVER: Preparing to restart..." 277 | while :; do sleep 60; done 278 | fi 279 | rm /tmp/rpiUpdate 280 | echo 281 | fi 282 | if [[ -f /tmp/noMacIP ]]; then 283 | echo 284 | echo "MacIP connections may be unavailable. If you know how, try" 285 | echo "recompiling the AppleTalk kernel module with IPDDP options disabled." 286 | echo 287 | rm /tmp/noMacIP 288 | fi 289 | 290 | if [[ -f /tmp/singleUser ]]; then 291 | if [[ ! $autoAnswerYes ]]; then 292 | echo 293 | echo "Your Raspberry Pi was started in single-user mode in order to" 294 | echo -n "fix a problem. You should restart to operate normally. Restart now? " 295 | read 296 | fi 297 | if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then 298 | sudo shutdown -r now 299 | echo 300 | echo "A2SERVER: Preparing to restart..." 301 | while :; do sleep 60; done 302 | fi 303 | rm /tmp/singleUser 304 | echo 305 | fi 306 | 307 | echo 308 | echo "Type 'system-shutdown' to turn off A2SERVER." 309 | echo "Type 'a2server-setup' to configure network boot." 310 | echo "Type 'a2server-help' for a list of other commands." 311 | fi 312 | fi 313 | 314 | unset a2server_update 2> /dev/null 315 | unset doSetup 2> /dev/null 316 | rm /tmp/a2server-* 2> /dev/null 317 | rm setup &> /dev/null 318 | -------------------------------------------------------------------------------- /update/devhistory.txt: -------------------------------------------------------------------------------- 1 | 1.0.0: Jan 2012: initial release 2 | 3 | 1.0.1: Jan 2012: fixes Netatalk date-stamp bug (thanks to Steven Hirsch) 4 | 5 | 1.0.2: Jan 2013: Netatalk 2.2.4; OS X 10.7+ login fixed; netboot fixes; 6 | Raspbian "Wheezy" support; Ubuntu 12.04 LTS support 7 | 8 | 1.1.0: Apr 2013: Full GS/OS install; eliminated GS.SYSTEM volume; 9 | Raspberry Pi enhancements; lots of improvements to installer; 10 | more utilities installed for Apple II; improved cppo 11 | NOTE: fresh install required, can't update earlier version 12 | 13 | 1.1.1: Jun 2013: Wi-Fi support; updates/additions to commands in a2server-help; 14 | bug fixes and improvements to install script; appletalk kernel 15 | module for Raspbian (instead of replacement kernel); RPi 16 | console (onboard serial) set to 19,200 bps during boot 17 | 18 | 1.1.2: Oct 2013: resolves issue of no AppleTalk in Raspbian 2013-09-10 and 19 | later; faster command-line installation on Raspberry Pi 20 | (nulib2 and unar binaries are downloaded rather than compiled) 21 | 22 | 1.1.3: Jan 2014: shares ADTPro disks folder as ADTDISKS; added environment 23 | variables for shared folders; can resolve by name 24 | "a2server.local" if network client has Bonjour/zeroconf; 25 | server presents itself as Shared computer to Macs on network; 26 | VM based on Debian 7 27 | 28 | 1.1.4: Jan 2014: fixes bug with network boot if ADTPro disks folder is shared 29 | 30 | 1.1.5: Jul 2014: a2server-setup fixes Raspbian 20-Jul-14 AppleTalk kernel panic 31 | 32 | 1.2.0: Aug 2014: a2server-setup and Netatalk startup script addresses AppleTalk 33 | kernel panic on any Linux kernel 3.12-3.15; Netatalk starts 34 | in background, preventing startup delay; a2server-setup always 35 | configures Netatalk startup script and can download a new one 36 | if missing; a2server-setup on Raspbian or Debian 7 x86 is 37 | faster because it downloads binaries rather than compiling 38 | from source; unbit/unexec/usq unarchivers added; additional 39 | virtual machine which has both A2SERVER and A2CLOUD installed 40 | 41 | 1.2.1: Jan 2015: minor fixes; support for LED blink on Raspbian 2015-01-31 42 | 43 | 1.2.2: Mar 2015: installer improvements: now has command line options, 44 | including unattended install; installer sets passwords 45 | automatically to 'apple2'; status messages are now prefixed by 46 | A2SERVER:; can update Raspple II (Raspbian OS, 47 | NOOBS install manager, A2SERVER, and A2CLOUD); minor fixes. 48 | 49 | 1.2.3: May 2015: changed Apple software links to Internet Archive 50 | 51 | 1.2.4: Jul 2015: offer to download A2CLOUD disk contents onto A2FILES volume 52 | 53 | 1.2.4+:Oct 2015: support for using A2SERVER scripts from a location other than 54 | [unannounced] ivanx.com/a2server for development purposes 55 | 56 | 1.2.5: Nov 2015: netboot install option for GS/OS 6.0.2/3 57 | netboot always downloads GS/OS disk images even if present 58 | provides error if a2setup doesn't have internet 59 | remove persisting a2server-setup options after aborted install 60 | fixed installer bug that omits first and last script elements 61 | download images from Apple, with Internet Archive as a backup 62 | install HFS.FST during netboot install 63 | 64 | 1.2.5+:Nov 2015: Merged Ivan's 1.2.5 release, removed support for Ubuntu for 65 | [unannounced] now (see RasppleII/a2server#11), patched ProDOS 8 in boot 66 | files for current year table, install unar from a package if 67 | it exists. 68 | 69 | 1.2.6: Nov 2015: full, ready to use install of Spectrum; install unzip 70 | [unannounced] 71 | 72 | 1.2.6+:Nov 2015: merged Ivan's 1.2.6 (into github master branch) 73 | [unannounced] 74 | 75 | 1.2.7: Dec 2015: preliminary Jessie support; case insensitive file system for 76 | [unannounced] A2FILES; removes GSFILES if empty; DOS3.3.FST and TEACH are 77 | installed with netboot installation; minor bug fixes and 78 | tweaks; Ubuntu support removed; branches unified 79 | 80 | 1.2.8: Dec 2015: can specify alternate host for binaries and external files; 81 | [unannounced] 64-bit Debian precompiled binaries; move /media/A2SHARED/* 82 | to /srv/A2SERVER; internet access (MacIP support); 83 | 84 | 1.2.9: Jan 2016: cppo supports ShrinkIt, DOS 3.3, DSK, 2MG; MountIt fully 85 | [unannounced] installed; nulib2 fixes handling empty forks (thanks Andy); 86 | -c installer option compiles all software (no binaries) 87 | 88 | 1.3.0: Jan 2016: Marinetti 3.0b8 installed, with preconfigured MacIP 89 | [unannounced] 90 | 91 | 1.3.1: Jan 2016: patch Prodos 8 Thunderclock year table based on current date 92 | [unannounced] 93 | 94 | 1.3.2: Jan 2016: install SAFE2, SAM2, and SNAP, configured for Apple II sites; 95 | [unannounced] -i installer option reinstalls A2SERVER 96 | 97 | 1.5.0: Jan 2016: defaults to GitHub for location of installer scripts 98 | [unannounced] 99 | 100 | 1.5.1: May 2016: changed URLs from rawgit.com to raw.githubusercontent.com 101 | to resolve https problems during install; OS X temp dir 102 | path corrected; added getexternal.sh to repo; 103 | cppo changes; minor text changes (JTC); better Debian 104 | version checking (JTC) 105 | [unannounced] 106 | 107 | 1.5.1r2: Oct 2017: set internal version to 1.5.1; expanded version history 108 | [unannounced] 109 | 110 | 1.5.2: Nov 2017: support for Stretch; suppress null byte read warnings in 111 | Bash 4.4; enable SSH server on Raspberry Pi if disabled; 112 | use Internet Archive backup URL's for external downloads if 113 | possible; compile AppleTalk kernel if -c flag is 114 | specified (rather than downloading); better cleanup after 115 | AppleTalk kernel compile; notification if AppleTalk kernel 116 | module doesn't load; fixed download links for comm software; 117 | bug fixes when compiling macipgw and ciopfs; 118 | os option (Raspbian update) removed from a2server-setup 119 | 120 | 1.5.3a1: July 2020: initial support for Debian/Raspbian Buster 121 | -------------------------------------------------------------------------------- /update/index.txt: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: 3 | 4 | # Ensure URL we'll use ends in a / 5 | case "$A2SERVER_SCRIPT_URL" in 6 | */) scriptURL="$A2SERVER_SCRIPT_URL" ;; 7 | *) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/NJRoadfan/a2server/currentdev}/" ;; 8 | esac 9 | 10 | currentVersion=$(wget -qO- "${scriptURL}setup/index.txt" | grep '^a2serverVersion' | cut -d '"' -f 2) 11 | 12 | if [[ -f /usr/local/etc/A2SERVER-version ]]; then 13 | installedVersion=$(cat /usr/local/etc/A2SERVER-version) 14 | else 15 | installedVersion=100 16 | fi 17 | 18 | autoAnswerYes= 19 | for arg in $@; do 20 | if [[ $arg == "-y" ]]; then 21 | autoAnswerYes=1 22 | break 23 | fi 24 | done 25 | 26 | echo 27 | echo "Update history:" 28 | wget -qO- "${scriptURL}update/versionhistory.txt" 29 | echo 30 | echo "installed version: ${installedVersion:0:1}.${installedVersion:1:1}.${installedVersion:2:1}" 31 | echo "current version: ${currentVersion:0:1}.${currentVersion:1:1}.${currentVersion:2:1}" 32 | echo 33 | if [[ $autoAnswerYes ]]; then 34 | REPLY="y" 35 | else 36 | echo -n "Do you want to update (or reinstall) A2SERVER? " 37 | read 38 | fi 39 | if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then 40 | # sudo rm /usr/local/etc/netatalk/a2boot/* &> /dev/null 41 | wget -q -O /tmp/setup "${scriptURL}setup/index.txt"; source /tmp/setup -i "$@" 42 | fi 43 | 44 | unset currentVersion 2> /dev/null 45 | unset installedVersion 2> /dev/null 46 | -------------------------------------------------------------------------------- /update/versionhistory.txt: -------------------------------------------------------------------------------- 1 | 1.0.0: Jan 2012: initial release 2 | 3 | 1.0.1: Jan 2012: fixes Netatalk date-stamp bug (thanks to Steven Hirsch) 4 | 5 | 1.0.2: Jan 2013: Netatalk 2.2.4; OS X 10.7+ login fixed; netboot fixes; 6 | Raspbian "Wheezy" support; Ubuntu 12.04 LTS support 7 | 8 | 1.1.0: Apr 2013: Full GS/OS install; eliminated GS.SYSTEM volume; 9 | Raspberry Pi enhancements; lots of improvements to installer; 10 | more utilities installed for Apple II; improved cppo 11 | NOTE: fresh install required, can't update earlier version 12 | 13 | 1.1.1: Jun 2013: Wi-Fi support; updates/additions to commands in a2server-help; 14 | bug fixes and improvements to install script; appletalk kernel 15 | module for Raspbian (instead of replacement kernel); RPi 16 | console (onboard serial) set to 19,200 bps during boot 17 | 18 | 1.1.2: Oct 2013: resolves issue of no AppleTalk in Raspbian 2013-09-10 and 19 | later; faster command-line installation on Raspberry Pi 20 | (nulib2 and unar binaries are downloaded rather than compiled) 21 | 22 | 1.1.3: Jan 2014: shares ADTPro disks folder as ADTDISKS; added environment 23 | variables for shared folders; can resolve by name 24 | "a2server.local" if network client has Bonjour/zeroconf; 25 | server presents itself as Shared computer to Macs on network; 26 | VM based on Debian 7 27 | 28 | 1.1.4: Jan 2014: fixes bug with network boot if ADTPro disks folder is shared 29 | 30 | 1.1.5: Jul 2014: a2server-setup fixes Raspbian 20-Jul-14 AppleTalk kernel panic 31 | 32 | 1.2.0: Aug 2014: a2server-setup and Netatalk startup script addresses AppleTalk 33 | kernel panic on any Linux kernel 3.12-3.15; Netatalk starts 34 | in background, preventing startup delay; a2server-setup always 35 | configures Netatalk startup script and can download a new one 36 | if missing; a2server-setup on Raspbian or Debian 7 x86 is 37 | faster because it downloads binaries rather than compiling 38 | from source; unbit/unexec/usq unarchivers added; additional 39 | virtual machine which has both A2SERVER and A2CLOUD installed 40 | 41 | 1.2.1: Jan 2015: minor fixes; support for LED blink on Raspbian 2015-01-31 42 | 43 | 1.2.2: Mar 2015: installer improvements: now has command line options, 44 | including unattended install; installer sets passwords 45 | automatically to 'apple2'; status messages are now prefixed by 46 | A2SERVER:; can update Raspple II (Raspbian OS, 47 | NOOBS install manager, A2SERVER, and A2CLOUD); minor fixes. 48 | 49 | 1.2.3: May 2015: changed Apple software links to Internet Archive 50 | 51 | 1.2.4: Jul 2015: install option for ProTERM, Z.Link, ADTPro, Spectrum images 52 | 53 | 1.2.5: Nov 2015: netboot install option for GS/OS 6.0.2/3; install HFS.FST 54 | during netboot install 55 | 56 | 1.2.6: Nov 2015: full, ready to use install of Spectrum 57 | [unannounced; released briefly, then withdrawn] 58 | 59 | 1.5.0: Jan 2016: mixed case filenames for A2FILES; remove GSFILES if empty; 60 | install Marinetti 3.0b8 with internet access via MacIP; 61 | fully install Spectrum, SAFE2, SAM2, SNAP, MountIt; install 62 | DOS3.3 and TEACH; remove Ubuntu support; move/media/A2SHARED/* 63 | to /srv/A2SERVER; faster install (precompiled binaries) on 64 | 64-bit Debian; cppo supports ShrinkIt, DOS 3.3, DSK, 2MG,mixed 65 | case filenames; nulib2 handles empty forks (thanks Andy); 66 | new installer options; patch P8 Thunderclock driver year table 67 | for current date; install from any host URL for development; 68 | source code at GitHub (thanks Joseph) 69 | 70 | 1.5.1: Jan 2016: fixed GitHub URLs to prevent https errors during installation 71 | (thanks to http://blogs.yahoo.co.jp/ushi_cow/57459736.html); 72 | bug fixes and minor text changes 73 | 74 | 1.5.1r2: Oct 2017: corrected version number 75 | 76 | 1.5.2: Nov 2017: support for Debian/Raspbian Stretch; fixes minor bugs during 77 | install; enable SSH server if disabled on Raspberry Pi; fixes 78 | changed download links for GS/OS communication software 79 | 80 | 1.5.3a2: July 2020: initial support for Debian/Raspbian Buster 81 | 82 | 1.5.5: April 2023: support for Debian/Raspbain Bullseye; 83 | added GS/OS 6.0.4 install option; 84 | added netatalk 2.2.6 patches for modern distros; 85 | fixed dead URLs for various utilities; 86 | fixed cppo's creation of AppleDouble headers; 87 | fixed appletalk kernel module compilation to work with linux 5.x; 88 | updated Marinetti and link Layers to latest releases; 89 | updated Spectrum to latest release; 90 | added The Networker2 and Webber installation 91 | 92 | 1.9.9: Oct 2024: added AFPBridge, NetDisk, and SMB FST installation; 93 | added TashRouter setup and TashTalk support on RPi; 94 | fixed bugs and updated cppo and afptype to support new 95 | versions of netatalk; 96 | fixed bugs in creation of ATINIT file; 97 | drop support for Debian 10 and older; 98 | updated to netatalk 2.4.10, switched to meson build; 99 | last release to use apple double v2 folders (i hope) 100 | 101 | Big thanks to: Anthony Martino, Henry Courbis, Joseph Carter, Jason King, 102 | Andy McFadden, Steven Hirsch, Geoff Body, Peter Wong, Tony Diaz, David Schmidt, 103 | David Schmenk, Ewen Wannop, Andrew Roughan, Antoine Vignau, Martin Haye, 104 | Ken Gagne, Peter Neubauer, James Littlejohn, Ninjaforce; the creators of 105 | Netatalk, The Unarchiver, ciopfs, macipgw; and the entire Apple II community. 106 | Redistribution of Spectrum, SAFE2, SAM2, SNAP by permission of Ewen Wannop. 107 | Thanks for using A2SERVER! 108 | --------------------------------------------------------------------------------