mirror of
				https://github.com/RasppleII/a2server.git
				synced 2025-10-30 23:16:08 +00:00 
			
		
		
		
	Compare commits
	
		
			89 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 27d40503be | ||
|  | 1c8acba1ae | ||
|  | 34836dcbb4 | ||
|  | 7b7917d417 | ||
|  | 938db3c46b | ||
|  | 4d1b5db5e3 | ||
|  | 7d1a06a916 | ||
|  | f9b120002a | ||
|  | 49d50e49ac | ||
|  | dfa1e26c80 | ||
|  | d86e3bfa88 | ||
|  | cd20570999 | ||
|  | cd8271cd56 | ||
|  | 750b9998df | ||
|  | 9ba5258fe0 | ||
|  | 50875f5c3f | ||
|  | ca4e3b76e6 | ||
|  | 3a82176d0a | ||
|  | 061c3c1897 | ||
|  | dea2ea2ce2 | ||
|  | bb5f42462e | ||
|  | 59d293ec84 | ||
|  | 9dfbe0e9f3 | ||
|  | ca12a4a9e9 | ||
|  | 94b6dcaa26 | ||
|  | da204bd05b | ||
|  | fbc1ce5ba2 | ||
|  | b7528026de | ||
|  | 60f88e4e8a | ||
|  | 13343a5c2a | ||
|  | 95fb701098 | ||
|  | 3a0e123c0a | ||
|  | 5c47545772 | ||
|  | c5460eb292 | ||
|  | 653218535f | ||
|  | a0ded5a7cf | ||
|  | 3cc2beabcf | ||
|  | 4ca810bd26 | ||
|  | f8d7a916e2 | ||
|  | 80c4818d47 | ||
|  | b846df61da | ||
|  | ec0bf3b9d5 | ||
|  | 631ad8a2e2 | ||
|  | 4ad9e10c77 | ||
|  | 9760380115 | ||
|  | 5660347bc8 | ||
|  | 6f835905af | ||
|  | 9bd8b0d3f0 | ||
|  | 9b87db8eb4 | ||
|  | 71274cb18f | ||
|  | 502e638964 | ||
|  | 85cbf4d741 | ||
|  | c5c14759d1 | ||
|  | 6e9ddb5e47 | ||
|  | 180dcc5634 | ||
|  | 7163390b19 | ||
|  | e0a78c5756 | ||
|  | 8327a5eb8d | ||
|  | 4a0d574f8a | ||
|  | e58fd1bbb1 | ||
|  | 02442b16e5 | ||
|  | 00adf2673d | ||
|  | fc7aaf4d53 | ||
|  | 0ca7ef94b8 | ||
|  | 1403fde73d | ||
|  | 7e12bbd696 | ||
|  | 1af347ae8f | ||
|  | 22020603f6 | ||
|  | 5fab6a21af | ||
|  | 6b45259759 | ||
|  | 4692537443 | ||
|  | 4e4bd8dbbd | ||
|  | d2775f4d27 | ||
|  | 8f6fae4bb4 | ||
|  | 53404e7784 | ||
|  | 01d3ce1775 | ||
|  | 14f5ef66be | ||
|  | 04ad897c97 | ||
|  | 06bc59ece7 | ||
|  | c2bb79860a | ||
|  | 343bde59fa | ||
|  | 024f579850 | ||
|  | 0fffaf93cb | ||
|  | 0bd95253fe | ||
|  | b5496b55aa | ||
|  | 9f397b1f9f | ||
|  | 435857e3bb | ||
|  | b0bb0e7b99 | ||
|  | bb9e458a98 | 
							
								
								
									
										13
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | License for A2SERVER | ||||||
|  | ==================== | ||||||
|  |  | ||||||
|  | A2SERVER | ||||||
|  |  | ||||||
|  | Copyright (C) 2013-2015 Ivan Drucker <ivan@ivanx.com> | ||||||
|  |  | ||||||
|  | The A2SERVER scripts themselves are written primarily by Ivan Drucker and | ||||||
|  | released under the WTFPL version 2, which you may download from its web page | ||||||
|  | at <http://www.wtfpl.net/txt/copying/>.  This is essentially a public domain | ||||||
|  | release, which doesn't extend to the other programs used by A2SERVER such as | ||||||
|  | netatalk or the various Linux tools it installs.  These have their own license | ||||||
|  | terms and Copyrights. | ||||||
							
								
								
									
										88
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								README.md
									
									
									
									
									
								
							| @@ -13,24 +13,84 @@ relatively modern piece of it.  As such they should be preserved as they are. | |||||||
|  |  | ||||||
| ## Developer note | ## Developer note | ||||||
|  |  | ||||||
| To use the scripts on a server other than Ivan's, you'll want to export | To use the scripts on your own server, including your local machine: | ||||||
| the shell variable A2SERVER_SCRIPT_URL to the base URL of this repository |  | ||||||
| on your server.  The base-URL should be slash-terminated.  You can then run |  | ||||||
| the following snippet: |  | ||||||
|  |  | ||||||
| ```bash | ~~~ bash | ||||||
| wget -O a2server-setup ${A2SERVER_SCRIPT_URL}setup/index.txt; source a2server-setup | export A2SERVER_SCRIPT_URL=http://yoururl.com/ | ||||||
| ``` | ~~~ | ||||||
|  |  | ||||||
| A simple method installing from a local folder is to change to that sudirectory | To prevent needing to recompile various packages from source code during | ||||||
| and run the following. Then export A2SERVER_SCRIPT_URL to "http://localhost:8000/" | installation, a number of precompiled binary files are downloaded for Raspbian, | ||||||
|  | Debian-x86, and Debian-amd64. If you wish to host these on your own server: | ||||||
|  |  | ||||||
| ```bash | ~~~ bash | ||||||
|  | export A2SERVER_BINARY_URL=http://yoururl.com/files/ | ||||||
|  | ~~~ | ||||||
|  |  | ||||||
|  | You do not need to use a subdirectory called "files", or the same server, but | ||||||
|  | that's the normal arrangement. The precompiled packages are available here: | ||||||
|  | `http://ivanx.com/a2server/files/dist/a2serverbinaries.tar.gz` | ||||||
|  |  | ||||||
|  | Several Apple II third-party binaries are downloaded during installation, as | ||||||
|  | well as third-party source code if precompiled binaries are unavailable or | ||||||
|  | you don't wish to use them. If you want these external dependencies locally | ||||||
|  | during development, they need to go into a folder called "external" in | ||||||
|  | the binaries URL, and that needs to contain folders called "appleii" and | ||||||
|  | "source". To download all of these external packages, download and run the | ||||||
|  | shell script at | ||||||
|  | `http://ivanx.com/a2server/files/dist/getexternal.sh`. | ||||||
|  |  | ||||||
|  | Once you have those: | ||||||
|  |  | ||||||
|  | ~~~ bash | ||||||
|  | export A2SERVER_NO_EXTERNAL=1 | ||||||
|  | ~~~ | ||||||
|  |  | ||||||
|  | You may want to put the above exports into `~/.bashrc` or `~/.bash_profile`. | ||||||
|  |  | ||||||
|  | If you want to host scripts locally installed on your own machine or another | ||||||
|  | computer on your LAN, type the following, and export "http://localhost:8000/" | ||||||
|  | or "http://lan.ip.address:8000/" for the above URL's. | ||||||
|  |  | ||||||
|  | ~~~ | ||||||
| python -m SimpleHTTPServer | python -m SimpleHTTPServer | ||||||
| ``` | ~~~ | ||||||
|  |  | ||||||
|  | Once you're set, you can then run the following snippet to install A2SERVER: | ||||||
|  |  | ||||||
|  | ~~~ | ||||||
|  | wget -O setup ${A2SERVER_SCRIPT_URL}setup/index.txt; source setup | ||||||
|  | ~~~ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Offline install: | ||||||
|  |  | ||||||
|  | Using locally hosted binaries and external dependencies, it's possible to | ||||||
|  | install completely offline if dependent packages have been installed. | ||||||
|  |  | ||||||
|  | If precompiled binaries are available, on Wheezy: | ||||||
|  |  | ||||||
|  | ~~~ | ||||||
|  | sudo apt-get -y install unzip libgnustep-base1.22 libdb5.1 libgcrypt11 libssl1.0.0 attr fuse libglib2.0-0 libattr1 libfuse2 | ||||||
|  | ~~~ | ||||||
|  |  | ||||||
|  | If precompiled binaries are available, on Jessie: | ||||||
|  |  | ||||||
|  | ~~~ | ||||||
|  | sudo apt-get -y install unzip unar libdb5.3 libgcrypt20 libssl1.0.0 attr fuse libglib2.0-0 libattr1 libfuse2 | ||||||
|  | ~~~ | ||||||
|  |  | ||||||
|  | If precompiled binaries are not available, on Wheezy: | ||||||
|  |  | ||||||
|  | ~~~ | ||||||
|  | sudo apt-get -y install unzip build-essential zlib1g-dev libgnustep-base-dev libz-dev libbz2-dev libssl-dev libicu-dev libdb5.1-dev libgcrypt11-dev libglib2.0-dev libattr1-dev libfuse-dev | ||||||
|  | ~~~ | ||||||
|  |  | ||||||
|  | If precompiled binaries are not available, on Jessie: | ||||||
|  |  | ||||||
|  | ~~~ | ||||||
|  | sudo apt-get -y install unzip unar build-essential zlib1g-dev unzip libssl-dev libdb5.3-dev libgcrypt11-dev libglib2.0-dev libattr1-dev libfuse-dev | ||||||
|  | ~~~ | ||||||
|  |  | ||||||
| You should probably export A2SERVER_SCRIPT_URL in your .bashrc or whatever |  | ||||||
| file configures your development environment.  Also be advised that as of |  | ||||||
| version 1.24 of A2SERVER, you must use the snippet above. |  | ||||||
|  |  | ||||||
| [Ivan's site]: http://appleii.ivanx.com/a2server/ | [Ivan's site]: http://appleii.ivanx.com/a2server/ | ||||||
|   | |||||||
| @@ -1,19 +0,0 @@ | |||||||
| # Ivan Drucker's A2SERVER documentation |  | ||||||
|  |  | ||||||
| A2SERVER was not so much planned as it was evolved.  It began as a project to |  | ||||||
| boot an Apple //e card in a Macintosh over AppleTalk using a small embedded |  | ||||||
| Linux-based computer and evolved over time into what it is today. |  | ||||||
|  |  | ||||||
| So too has its documentation.  And while one of the goals of this project is |  | ||||||
| to produce a full manual for A2SERVER, the pages on Ivan's website effectively |  | ||||||
| are a manual if you dig through them a bit. |  | ||||||
|  |  | ||||||
| More than that, Ivan's pages are a piece of recent Apple // history.  Future |  | ||||||
| endeavors may improve upon what is contained within those pages, but it will |  | ||||||
| not and indeed cannot replace them. |  | ||||||
|  |  | ||||||
| Thus the content of those pages as of mid-October 2015 (version 1.2.4) is |  | ||||||
| reproduced here in Markdown format in order to be most widely readable.  Where |  | ||||||
| unconvertable HTML with no direct non-HTML equivalent exists, this archive |  | ||||||
| will prefer readability to source accuracy.  Examples of this include things |  | ||||||
| such as replacing formatting using non-breaking spaces with an unordered list. |  | ||||||
| @@ -1,43 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| You probably want to be able to get stuff on and off of A2SERVER, so that |  | ||||||
| means connecting to it from other computers. |  | ||||||
|  |  | ||||||
| You can browse your network and you should see either "raspberrypi" or |  | ||||||
| "a2server" as a server you can connect to. You can log in as Guest if asked. |  | ||||||
|  |  | ||||||
| On Mac OS X, it should appear under Shared in the sidebar of a Finder window, |  | ||||||
| or under "Network" from the "Go" menu of the Finder. |  | ||||||
|  |  | ||||||
| On Windows, it should appear under Network. |  | ||||||
|  |  | ||||||
| On Mac OS 7 through 9, open Chooser from the Apple menu and click on |  | ||||||
| AppleShare. |  | ||||||
|  |  | ||||||
| (If you can't browse to the server on your network, you may need to [log in |  | ||||||
| to A2SERVER](a2server_commands.md) to update, and if that doesn't work, to |  | ||||||
| find its IP address. On Mac OS X, enter the IP address under "Connect To |  | ||||||
| Server..." from the Go menu of the Finder; on Windows, type the IP address |  | ||||||
| following two backslash characters (\\) in an Explorer window.) |  | ||||||
|  |  | ||||||
| <!-- |  | ||||||
| Content edit: Make sure both Markdown source and HTML target renderings of how |  | ||||||
| to specify a backslash-delimited UNC path are understandable.  -Joseph |  | ||||||
| --> |  | ||||||
|  |  | ||||||
| You will see two or three shared volumes: A2FILES, GSFILES, and, if you have |  | ||||||
| A2CLOUD installed, ADTDISKS. Avoid the A2FILES volume except for copying |  | ||||||
| things off of it. If you do want to put stuff on it, be careful to only use |  | ||||||
| ProDOS-compliant filenames (all caps, 15 characters max, starts with a letter, |  | ||||||
| and only contains letters/numbers/periods). Otherwise, you'll get unexpected |  | ||||||
| behavior like invisible files. |  | ||||||
|  |  | ||||||
| Unix-type computers can also use `scp` to copy files to and from A2SERVER; |  | ||||||
| Windows computers can also do so in the command window by using `pscp` in |  | ||||||
| [PuTTY][1]. The shared volumes are within /media/A2SHARED. |  | ||||||
|  |  | ||||||
| If you need to set the ProDOS file type of a file you have copied to A2SERVER, |  | ||||||
| [log in to A2SERVER](a2server_commands.md) and use `afptype`. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://www.chiark.greenend.org.uk/~sgtatham/putty/ |  | ||||||
| @@ -1,128 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| Sometimes you need to access the A2SERVER command line to set up network boot |  | ||||||
| or do other stuff. A list of commands is below. |  | ||||||
|  |  | ||||||
| If you are running A2SERVER on a Raspberry Pi without a screen and keyboard |  | ||||||
| attached, see how to |  | ||||||
| [log in to a Raspberry Pi](a2server_raspberrypi_login.md). |  | ||||||
|  |  | ||||||
| Otherwise, log in on your local console or virtual machine window, or via SSH |  | ||||||
| on another computer. On Mac OS X, or Windows with [Bonjour Print Services][1] |  | ||||||
| installed, you can use "raspberrypi.local" for your SSH address, or |  | ||||||
| "a2server.local" if not on a Pi. If that doesn't work, try updating |  | ||||||
| A2SERVER by typing `a2server-setup`. |  | ||||||
|  |  | ||||||
| If it still doesn't work, or you don't want to install Bonjour Print |  | ||||||
| services for Windows, you will need to use A2SERVER's IP address instead, |  | ||||||
| which you can see by typing `showip`. You can create a DHCP reservation in |  | ||||||
| your router to give A2SERVER the same IP address every time. To do this, |  | ||||||
| you'll need the MAC (Ethernet) address of the machine (or virtual machine) |  | ||||||
| running A2SERVER, which you can see by typing `showmac`. If you are using the |  | ||||||
| premade virtual machine, the MAC is 08:00:03:F2:FF:59 . |  | ||||||
|  |  | ||||||
| The default username is either "pi" for Raspberry Pi, and otherwise |  | ||||||
| "user1". The password is "apple2". (The password is "raspberry" for an |  | ||||||
| standard installation of Raspbian; you can use the |  | ||||||
| [installer script](a2server_installer.md) to install A2SERVER.) |  | ||||||
|  |  | ||||||
| Shared volumes can be found at /media/A2SHARED. Netatalk configuration files |  | ||||||
| are in /usr/local/etc/netatalk. |  | ||||||
|  |  | ||||||
| Once logged in, you can enter the following commands. |  | ||||||
|  |  | ||||||
| (If any of these yield "command not found", refresh the command list by |  | ||||||
| typing `a2server-setup`, answering "no" to all prompts if you like.) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ~~~ |  | ||||||
| A2SERVER commands: |  | ||||||
|   (note: new commands may be added; use a2server-setup to refresh) |  | ||||||
|  |  | ||||||
| a2server-help: show this list of commands |  | ||||||
| a2server-setup: set up network boot, Windows access, Farallon fix, |  | ||||||
|     refresh command list |  | ||||||
| a2server-version: see installed version of A2SERVER |  | ||||||
| a2server-update: check for update to A2SERVER |  | ||||||
|  |  | ||||||
| system-shutdown: shut down the server |  | ||||||
| system-restart: shut down and restart the server |  | ||||||
|  |  | ||||||
|  Raspberry Pi commands, if you're using one: |  | ||||||
| raspi-config: utilize all space on RPi SD card & other options |  | ||||||
| raspbian-update : update Raspbian operating system |  | ||||||
| rasppleii-update : update Raspbian OS, A2CLOUD, A2SERVER, Apple II Pi |  | ||||||
|  |  | ||||||
| welcome-message-edit: change the welcome message |  | ||||||
|  |  | ||||||
| showip: show the current ethernet IP address of the server |  | ||||||
| showmac: show the MAC (Ethernet hardware) address of the server |  | ||||||
| showip-wifi: show the current wifi IP address of the server |  | ||||||
| showmac-wifi: show the MAC (wifi hardware) address of the server |  | ||||||
| ifreset: reset all network interfaces (requires restart) |  | ||||||
|  |  | ||||||
| netatalk-stop: stop the netatalk service until reboot |  | ||||||
| netatalk-start: start the netatalk service |  | ||||||
| netatalk-restart: restart the netatalk service |  | ||||||
| netatalk-off: disable the netatalk service (even after reboot) |  | ||||||
| netatalk-on: enable the netatalk service |  | ||||||
|  |  | ||||||
| bonjour-off: disable advertisement of shared folders to OS X |  | ||||||
| bonjour-on : enable advertisement of shared folders to OS X |  | ||||||
|   (these are automatically set by the netatalk commands above) |  | ||||||
|  |  | ||||||
| netatalk-router-on: use netatalk in router mode (default) |  | ||||||
| netatalk-router-off: use netatalk in node mode |  | ||||||
|   (use if there is an AppleTalk router such as a GatorBox present) |  | ||||||
|  |  | ||||||
| netatalk-eth: use wired ethernet interface for netatalk (default) |  | ||||||
| netatalk-wifi: use wifi interface for netatalk |  | ||||||
|     note: if an interface isn't available, netatalk will be reset with |  | ||||||
|     router mode off; use "netatalk-router-on" to correct this if needed |  | ||||||
|  |  | ||||||
| appletalk-off: disable AppleTalk networking (even after reboot) |  | ||||||
| appletalk-on : enable AppleTalk networking |  | ||||||
|  |  | ||||||
| environment variables: |  | ||||||
| $NETATALK: directory containing netatalk configuration files |  | ||||||
| $A2FILES : directory containing A2FILES shared volume |  | ||||||
| $GSFILES : directory containing GSFILES shared volume |  | ||||||
|  |  | ||||||
| netboot-gsos: set the current user to netboot into GS/OS (default) |  | ||||||
| netboot-gsos-guest: set guests to netboot into GS/OS |  | ||||||
| netboot-p8: set the current user to netboot into ProDOS 8 |  | ||||||
| netboot-p8-guest: set guests to netboot into ProDOS 8 (default) |  | ||||||
|   note: when a IIgs is set to network boot into GS/OS, using the Network |  | ||||||
|   control panel or the NETBOOT.GSOS utility, guests will behave like |  | ||||||
|   registered users, and ignore the netboot setting of the guest user |  | ||||||
|  |  | ||||||
| guest-off: disallow guest access to A2SERVER |  | ||||||
| guest-on: allow guest access to A2SERVER (default) |  | ||||||
|   note: by default, Guest access is the only way to network boot into |  | ||||||
|   ProDOS 8. For registered user boot into ProDOS 8, type "netboot-p8" |  | ||||||
|  |  | ||||||
| samba-off: disable Windows file sharing (even after reboot) |  | ||||||
| samba-on: enable Windows file Sharing |  | ||||||
| samba-stop: stop Windows file sharing until reboot |  | ||||||
| samba-start: start Windows file sharing |  | ||||||
| samba-restart: stop and restart Windows file sharing |  | ||||||
|  |  | ||||||
| gsfiles-share: disable the GSFILES shared volume |  | ||||||
| gsfiles-unshare: enable the GSFILES shared volume |  | ||||||
| a2files-share: disable the A2FILES shared volume |  | ||||||
| a2files-unshare: enable the A2FILES shared volume |  | ||||||
|  |  | ||||||
| nulib2: create, extract, and work with NuFX (ShrinkIt) archive files |  | ||||||
| unar: extract other archive files (multiformat) |  | ||||||
| lsar: list contents of other archive files (multiformat) |  | ||||||
|  |  | ||||||
| afptype: set the ProDOS type/auxtype or Mac OS type/creator of a file |  | ||||||
| afpsync: register files introduced outside of AFP with netatalk |  | ||||||
| mkatinit: set up network boot configuration files |  | ||||||
| cppo: catalog and copy files from ProDOS image file (slow, but works) |  | ||||||
|   (add -h to show help for the above four commands, e.g. "afptype -h") |  | ||||||
|  |  | ||||||
| ~~~ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://support.apple.com/kb/dl999 |  | ||||||
| @@ -1,84 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| A2SERVER's central capability, sharing files to an Apple II, is provided by |  | ||||||
| [Netatalk][1] 2.2.4. |  | ||||||
|  |  | ||||||
| Here's the extra sauce that A2SERVER provides: |  | ||||||
|  |  | ||||||
| * available as a ready-to-use [Raspberry Pi][2] operating system installer |  | ||||||
|  |  | ||||||
|   (plus new [Pi Filler][3] and [Pi Copier][3] utilities for easy SD card |  | ||||||
|   creation and backup) |  | ||||||
|  |  | ||||||
| * available as a ready-to-use [VirtualBox][4] appliance for Mac OS X, Windows, |  | ||||||
|   Linux, and Solari |  | ||||||
|  |  | ||||||
| * simple downloadable installation script for Ubuntu Linux or Raspbian takes |  | ||||||
|   care of setting up and configuring *everything* |  | ||||||
|  |  | ||||||
| * enables reliable operation by Asante, Farallon and Dayna bridges on both IIe |  | ||||||
|   *and* IIgs \[fixes contributed by Steven Hirsch and Geoff Body\] |  | ||||||
|  |  | ||||||
| * easy to configure for network boot, including ProDOS 8 and GS/OS download |  | ||||||
|   and installation |  | ||||||
|  |  | ||||||
| * can network boot both IIe and IIgs computers on the same network |  | ||||||
|  |  | ||||||
| * new ProDOS 8 tools (NETBOOT.P8 and NETBOOT.GSOS) for setting the IIg network |  | ||||||
|   boot default |  | ||||||
|  |  | ||||||
| * temporary ProDOS 8 network boot without changing GS/OS default \[contributed |  | ||||||
|   by Geoff Body\] |  | ||||||
|  |  | ||||||
| * GS/OS installer that can be run from folders rather than disk |  | ||||||
|  |  | ||||||
| * installs ProDOS 8 and GS/OS utilities for working with archive (ShrinkIt and |  | ||||||
|   GSHK), disk images ([DSK2FILE][5] / [Asimov][6] / [MountIt][7]), and file |  | ||||||
|   (Apple ProDOS System Utilities) |  | ||||||
|  |  | ||||||
| * supports Wi-Fi when used with Apple AirPort or Time Capsul |  | ||||||
|  |  | ||||||
| * maintains correct dates during GS/OS folder copy \[fix contributed by Steven |  | ||||||
|   Hirsch\] |  | ||||||
|  |  | ||||||
| * uses randnum authentication for registered user sign-in (which alway works, |  | ||||||
|   unlike cleartext) |  | ||||||
|  |  | ||||||
| * supports login to shared volumes from latest versions of OS X and Window |  | ||||||
|  |  | ||||||
| * new Linux tool ([afptype](scripts/tools/afptype.txt)) for setting ProDOS or |  | ||||||
|   classic Mac file types on shared volume |  | ||||||
|  |  | ||||||
| * new Linux tool ([cppo](scripts/tools/cppo.txt)) for cataloging and copying |  | ||||||
|   files (with optional resource forks) out of ProDOS disk image |  | ||||||
|  |  | ||||||
| * [Linux commands](a2server_commands.md) to ease server maintenanc |  | ||||||
|  |  | ||||||
| * installs Linux tools for working with ShrinkIt and other old and new archive |  | ||||||
|   formats ([nulib2][8] and [unar/lsar][9]) |  | ||||||
|  |  | ||||||
| <!-- |  | ||||||
| * sets up Raspberry Pi for shell login from Apple II via USB-serial cable or |  | ||||||
|   Raspberry Pi console cable |  | ||||||
| --> |  | ||||||
|  |  | ||||||
| * blinks Raspberry Pi OK/ACT LED for ten seconds when netatalk has just |  | ||||||
|   started |  | ||||||
|  |  | ||||||
| * good documentation (or so I hope) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Any content unique to A2SERVER and not covered under a specific license is |  | ||||||
| licensed under the [WTFPL][10]. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://netatalk.sourceforge.net |  | ||||||
| [2]: http://www.raspberrypi.org |  | ||||||
| [3]: http://ivanx.com/raspberrypi/ |  | ||||||
| [4]: http://www.virtualbox.org |  | ||||||
| [5]: http://www.dwheeler.com/6502/oneelkruns/dsk2file.html |  | ||||||
| [6]: http://www.ninjaforce.com/html/products.html |  | ||||||
| [7]: http://www.brutaldeluxe.fr/products/apple2gs/mountit.html |  | ||||||
| [8]: http://www.nulib.com |  | ||||||
| [9]: http://unarchiver.c3.cx |  | ||||||
| [10]: http://www.wtfpl.net |  | ||||||
| @@ -1,63 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| To connect to A2SERVER from your Apple II: |  | ||||||
|  |  | ||||||
| (An alternative to the below is to [boot your Apple II over the |  | ||||||
| network](a2server_netboot.md) -- check that out too.) |  | ||||||
|  |  | ||||||
| Start up A2SERVER and wait (potentially up to a minute) until you get to the |  | ||||||
| login prompt. You do not need to log in. On a Raspberry Pi, you can see that |  | ||||||
| it's ready when the the normally irregular ACT or OK LED blinks steadily and |  | ||||||
| rapidly for ten seconds. |  | ||||||
|  |  | ||||||
| If you are on a IIe, boot from the [Workstation Card disk](#wsdisks), and |  | ||||||
| choose "Log On". |  | ||||||
|  |  | ||||||
| If you are on a IIgs, open the AppleShare control panel. If you don't have |  | ||||||
| it, use the GS/OS installer disks to custom install the script called |  | ||||||
| "Network: AppleShare" to your startup disk. If you are on a floppy-only |  | ||||||
| system, you can instead use the script "Network: AppleShare, 3.5" disk" to |  | ||||||
| make a bootable disk, or consider setting up |  | ||||||
| [network boot](a2server_netboot.md). |  | ||||||
|  |  | ||||||
| (There is also an obsolete [IIgs Workstation Disk](#wsdisks) that boots into |  | ||||||
| ProDOS 16 rather than GS/OS, and has the same ProDOS 8 applications for server |  | ||||||
| access as the IIe disk. You probably don't want to use it.) |  | ||||||
|  |  | ||||||
| "a2server" or "raspberrypi" should appear in the list of server names. Log |  | ||||||
| in as Guest and select the A2FILES volume, for ProDOS 8 storage, and/or the |  | ||||||
| GSFILES volume, for GS/OS storage. (You can also log in as a registered user, |  | ||||||
| but it's exactly the same.) |  | ||||||
|  |  | ||||||
| On the A2FILES volume, filenames need to be all caps and are subject to the |  | ||||||
| usual ProDOS restrictions (letters/numbers/periods only, first character must |  | ||||||
| be a letter, 15 characters max). IIgs users can store files on GSFILES with |  | ||||||
| mixed case, punctuated names of up to 31 characters (same as a classic Mac). |  | ||||||
|  |  | ||||||
| The network volumes hosted by A2SERVER will appear on the Finder desktop in |  | ||||||
| GS/OS; in ProDOS 8, you can type `PREFIX /A2FILES`. |  | ||||||
|  |  | ||||||
| ### Workstation Software:  {#wsdisk} |  | ||||||
|  |  | ||||||
| <!-- |  | ||||||
| FIXME: These disk images are not (at present) contained within this archive. |  | ||||||
| Moreover, they cannot be directly included in properly "Open Source" packages |  | ||||||
| of A2SERVER which ought to include this archive.  They'll have to be external |  | ||||||
| links, but I'm not fixing that right now.  -tjcarter,2015-10-22 |  | ||||||
| --> |  | ||||||
|  |  | ||||||
| * IIe Workstation Card, 800K: |  | ||||||
|   [raw image](files/a2ws/A2E.WS.FULL.HDV) |  | ||||||
|   [ShrinkIt image](files/a2ws/A2E.WS.FULL.BXY) |  | ||||||
|  |  | ||||||
| * IIe Workstation Card, Logon/Logoff/BASIC only, 140K: |  | ||||||
|   [raw image](files/a2ws/A2E.WS.LITE.DSK) |  | ||||||
|   [ShrinkIt image](files/a2ws/A2E.WS.LITE.BXY) |  | ||||||
|  |  | ||||||
| * IIe Workstation Card, System Utilities/BASIC only, 140K: |  | ||||||
|   [raw image](files/a2ws/A2E.WS.UTIL.DSK) |  | ||||||
|   [ShrinkIt image](files/a2ws/A2E.WS.UTIL.BXY) |  | ||||||
|  |  | ||||||
| * IIgs Workstation, 800K \[superseded by GS/OS AppleShare software\]: |  | ||||||
|   [raw image](files/a2ws/A2GS.WS.HDV) |  | ||||||
|   [ShrinkIt image](files/a2ws/A2E.WS.BXY) |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| You can easily install A2SERVER on Debian, Ubuntu, or Raspbian Linux by using |  | ||||||
| the A2SERVER install scripts. |  | ||||||
|  |  | ||||||
| While these are the only Linux distributions the scripts have been tested on, |  | ||||||
| other Debian-derived distributions may work as well, provided they're not |  | ||||||
| based on Debian 8, don't use kernel 3.12 through 3.15, have AppleTalk |  | ||||||
| networking support available as a kernel module or compiled into the kernel |  | ||||||
| itself, and their repositories contain the packages the scripts require. The |  | ||||||
| user running the scripts needs a bash shell, sudo privileges, and a search |  | ||||||
| path containing all the "bin" and "sbin" directories. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Debian or Ubuntu Linux |  | ||||||
|  |  | ||||||
| (Tested on Debian 7.8.0 and Ubuntu Server 12.04 LTS. Note that Ubuntu 14.04 |  | ||||||
| LTS includes kernel 3.13, which is *not* compatible with A2SERVER; you will |  | ||||||
| need to upgrade it to 3.16 or later. Debian 8 and Ubuntu 15 *cannot* be used |  | ||||||
| at this time.) |  | ||||||
|  |  | ||||||
| 1. [Create a new virtual machine](a2server_prepvm.md) (skip if installing on a |  | ||||||
|    real machine) |  | ||||||
| 2. [Install Debian](a2server_installubuntu.md) (or Ubuntu) on the virtual or |  | ||||||
|    real machine |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Raspberry Pi |  | ||||||
|  |  | ||||||
| 1. [Download Raspbian][1] |  | ||||||
| 2. [Perform Raspberry Pi setup](a2server_raspberrypi.md) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Once you are up and running in Linux, you can execute the automated setup |  | ||||||
| scripts to download, install, and configure the A2SERVER software. To use |  | ||||||
| these, [log in to Linux](a2server_commands.md), and type: |  | ||||||
|  |  | ||||||
| ~~~ bash |  | ||||||
| wget appleii.ivanx.com/a2server/setup; source setup |  | ||||||
| ~~~ |  | ||||||
|  |  | ||||||
| Confirm that you want to proceed, enter the password again, and go get a |  | ||||||
| sandwich, but come back so you can answer questions when prompted. |  | ||||||
|  |  | ||||||
| Once it's done, check out the links on the [A2SERVER home page](index.md) for |  | ||||||
| next steps. |  | ||||||
|  |  | ||||||
| If you'd like to set things up manually, or are curious as to what's |  | ||||||
| happening, you can |  | ||||||
| [view the contents of the setup scripts](a2server_scriptdetails.md). |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://www.raspberrypi.org/downloads |  | ||||||
| @@ -1,58 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
|  These steps cover how to install Ubuntu Server Linux into your empty virtual or real machine. (The instructions are similar, but may vary somewhat, for Debian Linux.) |  | ||||||
|  |  | ||||||
| * Download [Ubuntu Server 12.04 LTS][1], and burn it to a CD if |  | ||||||
|   installing on a real machine; otherwise, attach the download to your |  | ||||||
|   virtual machine's CD/DVD drive. |  | ||||||
|  |  | ||||||
| * Click Start. |  | ||||||
|  |  | ||||||
| * Answer all the region related questions and choose to Install Ubuntu |  | ||||||
|   Server. |  | ||||||
|  |  | ||||||
| * For hostname, enter *a2server* |  | ||||||
|  |  | ||||||
| * Under Partition Disks, choose "Guided - use entire disk" (no LVM). |  | ||||||
|  |  | ||||||
| * Choose SCSI1 (or whatever other disk appears), and (two screens later) |  | ||||||
|   confirm "Write the changes to disks." |  | ||||||
|  |  | ||||||
| * If you are installing Debian, and are prompted for a domain name or |  | ||||||
|   the root user password, leave them blank. |  | ||||||
|  |  | ||||||
| * Enter *user1* as the full name for the new user, and as the username |  | ||||||
|   for your account |  | ||||||
|  |  | ||||||
| * Choose *apple2* as the password, verify by retyping, and then confirm |  | ||||||
|   weak password |  | ||||||
|  |  | ||||||
| * Choose not to encrypt your home directory |  | ||||||
|  |  | ||||||
| * If you require an HTTP proxy, enter it, or leave it blank if not. |  | ||||||
|  |  | ||||||
| * Choose yes to Install the GRUB boot loader to the master boot record |  | ||||||
|  |  | ||||||
| * Choose no automatic updates |  | ||||||
|  |  | ||||||
| * Choose OpenSSH under Software Selection (and, for Debian, Standard |  | ||||||
|   System Utilities) |  | ||||||
|  |  | ||||||
| * Click Continue to reboot |  | ||||||
|  |  | ||||||
| * When prompted, log in with username *user1* and password *apple2*. |  | ||||||
|  |  | ||||||
| * If you installed Debian rather than Ubuntu, type: |  | ||||||
|    |  | ||||||
|   ~~~ bash |  | ||||||
|   sudo sed -i '0,/-eq 0/s/-eq 0/-ge 0/' /etc/profile |  | ||||||
|   ~~~ |  | ||||||
|  |  | ||||||
| * When you're back at the prompt, type `sudo shutdown -h now` which |  | ||||||
|   will turn off the (virtual) machine. |  | ||||||
|  |  | ||||||
| * Recommended: If you are using a virtual machine, take a snapshot you |  | ||||||
|   can return to this point if necessary. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://www.ubuntu.com/download/server/download |  | ||||||
| @@ -1,122 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| In order to connect your Apple II to the network, you need a LocalTalk to |  | ||||||
| Ethernet bridge. (Unfortunately, the [Uthernet card][1] will not work, as |  | ||||||
| Apple's network drivers don't know what it is.) |  | ||||||
|  |  | ||||||
| If you have an enhanced Apple IIe, you will also need an [Apple II Workstation |  | ||||||
| Card][2], and, if you're not booting over the network, the [Workstation Card |  | ||||||
| software](a2server_howtouse.html#wsdisks). Make sure you buy one with the |  | ||||||
| dongle. \[ <!-- [Blujay][3] --> [eBay][4] \] |  | ||||||
|  |  | ||||||
| These are the commonly available bridges; be sure you read below about their |  | ||||||
| idiosyncracies before you buy one. |  | ||||||
|  |  | ||||||
| * Asante [AsanteTalk][5] and AsantePrint \[ [Asante][6] [eBay][7] \] |  | ||||||
|  |  | ||||||
| * Dayna EtherPrint and Mini EtherPrint (any model with an Ethernet port)    |  | ||||||
|   \[ [eBay][8] \] |  | ||||||
|  |  | ||||||
| * Farallon EtherWave/EtherMac/iPrint LT with LocalTalk (PN842, PN848 or |  | ||||||
|   PN559) \[ [eBay][9] \] |  | ||||||
|  |  | ||||||
| * A pre-USB Mac with any kind of Ethernet, and the [LocalTalk Bridge][10] |  | ||||||
|   control panel installed \[ [eBay][11] \] |  | ||||||
|  |  | ||||||
| You'll also need an ImageWriter II printer cable (or any other 8-pin mini-DIN |  | ||||||
| null-modem serial cable), or two LocalTalk transceivers joined by either a |  | ||||||
| LocalTalk cable or four-wire phone cord, depending on whether you have Apple |  | ||||||
| or PhoneNet transceivers. (PhoneNet transceivers also require a terminator at |  | ||||||
| both ends; it looks like a phone plug with a resistor sticking out of it.) |  | ||||||
| Connect each end to your Apple II and the bridge, and an Ethernet cable |  | ||||||
| between the bridge and your router. |  | ||||||
|  |  | ||||||
| For an Apple IIgs, go to the Slots control panel by pressing ctrl-Apple-ESC, |  | ||||||
| and set slot 1 or 2, depending on whether you are using the printer or modem |  | ||||||
| port for networking, to "Your Card" (ROM 01 machines) or "AppleTalk" (ROM |  | ||||||
| 3 machines), and set slot 7 to "AppleTalk" (ROM 01 machines only). For an |  | ||||||
| Apple IIe, install the Workstation Card in any slot, and be sure to connect |  | ||||||
| your LocalTalk cable to the port with the double-arrow icon. |  | ||||||
|  |  | ||||||
| If you have multiple Apple II's you'd like to network, you can use a bridge |  | ||||||
| for each, or a single bridge attached to daisy-chained LocalTalk transceivers. |  | ||||||
|  |  | ||||||
| Wired ethernet is recommended, but if you have an Apple AirPort or Time |  | ||||||
| Capsule, you can use Wi-Fi by attaching your LocalTalk-to-Ethernet bridge to a |  | ||||||
| another AirPort, and setting up an [extended network][12] (if all AirPorts are |  | ||||||
| 802.11n models), or a [WDS][13] (if any AirPort is an 802.11g model). (Most |  | ||||||
| non-Apple routers and access points will not work because they are not |  | ||||||
| designed to handle AppleTalk networking.) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Caveat emptor: |  | ||||||
|  |  | ||||||
| * The AsanteTalk must be powered on while A2SERVER is up and running, or it |  | ||||||
|   will enter a mode where it won't operate correctly. (On the AsanteTalk, you |  | ||||||
|   will know it entered the right mode if the TX light blinks a lot during |  | ||||||
|   power-up. If it instead pulses only two or three times, then goes dark for a |  | ||||||
|   little while, and then pulses very rapidly for about three seconds, you'll |  | ||||||
|   need to remove power, make sure A2SERVER is running, and try again.) |  | ||||||
|  |  | ||||||
| * At least some of the Dayna bridges must be attached to a 10Base-T Ethernet |  | ||||||
|   port; they won't work if attached to an autosensing 10/100 or Gigabit |  | ||||||
|   Ethernet port such as those found on modern routers and switches. You can |  | ||||||
|   [buy a 10Base-T hub on eBay][14] for around $10 to go between your router |  | ||||||
|   and the bridge. |  | ||||||
|  |  | ||||||
| * Farallon bridges work fine with an Apple IIe. To prevent them from freezing |  | ||||||
|   a IIgs after a couple of minutes, you can download a fix for GS/OS ([disk |  | ||||||
|   image][15] or [ShrinkIt][16] format) and put it into SYSTEM/SYSTEM.SETUP, or |  | ||||||
|   you can [log in to the A2SERVER console](a2server_commands.html) and type |  | ||||||
|   `a2server-setup` and you will be asked if you want to install it. Because |  | ||||||
|   the fix is for GS/OS only, Farallon bridges will *not* work with a IIgs |  | ||||||
|   booted directly into ProDOS 8. (Also note: the PN842 has a built-in 8-pin |  | ||||||
|   cable, and the PN848 and PN559 have a built-in PhoneNet terminated |  | ||||||
|   transceiver, so you might not need all the cabling described above.) |  | ||||||
|  |  | ||||||
| * Using a classic Mac as a bridge works perfectly in all cases. Set AppleTalk |  | ||||||
|   to use the Ethernet port, attach the LocalTalk tranceiver or serial cable to |  | ||||||
|   the printer port (or printer/modem port), and install [LocalTalk |  | ||||||
|   Bridge][10]. (Recommended models: PowerBook 3400 with Ethernet, PowerBook G3 |  | ||||||
|   with black keyboard. Any model with both a round serial port and any kind of |  | ||||||
|   Ethernet, including via expansion card, AAUI adapter, or SCSI adapter, |  | ||||||
|   should work.) |  | ||||||
|  |  | ||||||
| And finally: |  | ||||||
|  |  | ||||||
| * The Cayman GatorBox CS and the Shiva FastPath IV and V have been reported to |  | ||||||
|   work, but it's hard to find these, so I have been unable to test. If you |  | ||||||
|   have one of these and it doesn't work, [log in](a2server_commands.html) to |  | ||||||
|   A2SERVER and type `netatalk-router-off` (if you get "command not found", |  | ||||||
|   type `a2server-setup` to refresh the command list). |  | ||||||
|  |  | ||||||
| * Other LocalTalk-to-Ethernet routers and bridges may work too, but haven't |  | ||||||
|   been tested by me. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Thank you: |  | ||||||
|  |  | ||||||
| Many thanks to Steven Hirsch, who fixed the Netatalk code in A2SERVER to make |  | ||||||
| the Asante bridges start up reliably, and prevent the Dayna bridges from |  | ||||||
| crashing the computer in GS/OS; and many thanks to Geoff Body, who contributed |  | ||||||
| the patch to GS/OS to make Farallon bridges work reliably without freezing a |  | ||||||
| IIgs after a few minutes. Also, thanks to all who have tested and sent reports |  | ||||||
| on using A2SERVER with their bridges. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://a2retrosystems.com/ |  | ||||||
| [2]: http://www.apple2info.net/hardware/a2ews/a2ews.htm |  | ||||||
| [3]: http://www.blujay.com/?keywords=workstation+card&Search.x=0&Search.y=0&Search=Search&page=search |  | ||||||
| [4]: http://www.ebay.com/sch/i.html?_nkw=apple+workstation+card+-portrait |  | ||||||
| [5]: http://www.asante.com/products/Asantetalk/Asantetalk.asp |  | ||||||
| [6]: http://www.asante.com/shop/shopdisplayproducts.asp?id=16&cat=+AsanteTalk |  | ||||||
| [7]: http://www.ebay.com/sch/i.html?_nkw=%28asantetalk%2C+asanteprint%29 |  | ||||||
| [8]: http://www.ebay.com/sch/i.html?_nkw=etherprint |  | ||||||
| [9]: http://www.ebay.com/sch/i.html?_nkw=farallon+%28etherwave%2Cethermac%2Ciprint%29+-sl+-aui+-aaui+-pci+-nubus+-pds+-card |  | ||||||
| [10]: 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%2FMacintosh%2FNetworking-Communications%2FOther_N-C%2FLocalTalk_Bridge_2.1.smi.bin |  | ||||||
| [11]: http://www.ebay.com/sch/i.html?_nkw=powerbook%20(3400c%2Cg3)%20-adapter%20-pismo%20-lombard%20-bronze%20-ibook%20-g4%20-333%20-333mhz%20-400%20-400mhz%20-500%20-500mhz |  | ||||||
| [12]: http://support.apple.com/kb/HT4259 |  | ||||||
| [13]: http://support.apple.com/kb/HT4262 |  | ||||||
| [14]: http://www.ebay.com/sch/i.html?_odkw=10base-t+%28hub%2Cswitch%29+-fast+-100+-1000+-gigabit |  | ||||||
| [15]: http://appleii.ivanx.com/a2server/files/FARALLON.B1.PO |  | ||||||
| [16]: http://appleii.ivanx.com/a2server/files/FARALLON.B1.BXY |  | ||||||
| @@ -1,48 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| You can set up A2SERVER to let your Apple IIgs or IIe boot into GS/OS or |  | ||||||
| ProDOS 8 over the network, rather than from a local drive. It can even |  | ||||||
| download and install ProDOS 8 and GS/OS for you, meaning you can get up and |  | ||||||
| running from "bare metal" if you wanted to. |  | ||||||
|  |  | ||||||
| To do this, [log into the a2server console](a2server_commands.md), and type: |  | ||||||
|  |  | ||||||
| ~~~ bash |  | ||||||
| a2server-setup |  | ||||||
| ~~~ |  | ||||||
|  |  | ||||||
| After confirming that you want to proceed, you will be asked if you want to |  | ||||||
| set up A2SERVER for network boot. Just follow the prompts. If you elect to |  | ||||||
| install GS/OS, be prepared to wait for a while. You will also be given the |  | ||||||
| option to install various utilities (GSHK, Asimov, and MountIt for GS/OS; |  | ||||||
| ShrinkIt, DSK2FILE, and Apple System Utilities for ProDOS 8.) |  | ||||||
|  |  | ||||||
| For an Apple IIgs, set the startup slot to Slot 7 (ROM 01) or AppleTalk (ROM |  | ||||||
| 3). For an Apple IIe, put the Workstation Card in a slot higher than any other |  | ||||||
| drive interface card, or type PR#x where x is the slot number; you must hold |  | ||||||
| down the Open-Apple key when you press return. |  | ||||||
|  |  | ||||||
| When your Apple II boots up, it will try to boot from the network. If it's |  | ||||||
| working, you'll see a flashing asterisk on a IIe, or a progression of periods |  | ||||||
| at the upper left of the screen on a IIgs. You may or may not be asked to |  | ||||||
| choose "a2server" or "raspberrypi" as your server. |  | ||||||
|  |  | ||||||
| Log in as Guest and select the A2FILES volume, and also the GSFILES volume if |  | ||||||
| you're using a IIgs. (If you are booting into GS/OS, you can also log in as a |  | ||||||
| registered user, but it's exactly the same.) |  | ||||||
|  |  | ||||||
| ProDOS 8 and GS/OS are stored on the volume /A2FILES; filenames are all caps |  | ||||||
| and subject to the usual ProDOS restrictions. IIgs users can store files on |  | ||||||
| the volume /GSFILES with mixed case, punctuated names of up to 31 characters. |  | ||||||
|  |  | ||||||
| If you installed GS/OS, you'll see a folder called GSOS.INSTALLER. In there, |  | ||||||
| IMAGES contains all the GS/OS floppies, which can be turned back into disks by |  | ||||||
| using Asimov in the IMAGE.TOOLS folder. You can also use run the GS/OS |  | ||||||
| installer from the NET.INSTALL folder instead of using disks. |  | ||||||
|  |  | ||||||
| A IIgs can network boot into either GS/OS or ProDOS 8 by default, which you |  | ||||||
| specify in the Network control panel of GS/OS, or within ProDOS 8 by running |  | ||||||
| NETBOOT.GSOS or NETBOOT.P8, which you'll find in A2FILES (both reboot the |  | ||||||
| computer immediately). You can temporarily network boot into ProDOS 8, without |  | ||||||
| changing the GS/OS default, by pressing "8" while the dots are filling in |  | ||||||
| during the first phase of the network boot (thanks to Geoff Body for this). |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| The following steps explain how to prep the A2SERVER virtual machine, |  | ||||||
| specifically [VirtualBox][1], which has the notable virtue of being free. |  | ||||||
| However, you can also use other virtual machine products, such as those from |  | ||||||
| [Parallels][2] and [VMware][3], and the process should be similar. |  | ||||||
|  |  | ||||||
| If you're comfortable doing so, you may also customize the steps below as you |  | ||||||
| wish, or install Ubuntu Linux natively rather than in a VM. |  | ||||||
|  |  | ||||||
| * Download [VirtualBox 4.2.10][4]. |  | ||||||
|  |  | ||||||
| * Download [Ubuntu Server 12.04 LTS][5] (A2SERVER has been tested with the |  | ||||||
|   32-bit version only). |  | ||||||
|  |  | ||||||
| * Start VirtualBox, and go to Preferences. |  | ||||||
|  |  | ||||||
| * Click Input. Set the host key to right-alt, and uncheck Auto Capture |  | ||||||
|   Keyboard. |  | ||||||
|  |  | ||||||
| * Click OK. |  | ||||||
|  |  | ||||||
| * Click New to create a new virtual machine. |  | ||||||
|  |  | ||||||
| * Enter *A2SERVER* as the VM name, and select Linux/Ubuntu as the operating |  | ||||||
|   system. |  | ||||||
|  |  | ||||||
| * Enter 256 MB for memory. |  | ||||||
|  |  | ||||||
| * Under Virtual Hard Disk, leave the defaults (Start-up Disk, and Create new |  | ||||||
|   hard disk). |  | ||||||
|  |  | ||||||
| * Choose VMDK for hard disk file type. |  | ||||||
|  |  | ||||||
| * Leave the virtual disk file as Dynamically allocated. |  | ||||||
|  |  | ||||||
| * Leave the virtual disk file location as A2SERVER, and set the disk size to |  | ||||||
|   32 GB. |  | ||||||
|  |  | ||||||
| * Click Create, and then again in the next window. |  | ||||||
|  |  | ||||||
| * Click Settings. |  | ||||||
|  |  | ||||||
| * Click Storage. Click on \"Empty\" under \"IDE Controller\". |  | ||||||
|  |  | ||||||
| * Click on the small CD icon on the far right of the window, select \"Choose a |  | ||||||
|   virtual CD/DVD disk file...\", and choose the Ubuntu Server file you |  | ||||||
|   downloaded. |  | ||||||
|  |  | ||||||
| * Click Network. |  | ||||||
|  |  | ||||||
| * Change \"Attached To:\" to \"Bridged Adapter\". |  | ||||||
|  |  | ||||||
| * Change \"Name:\" to a **wired** network interface on your computer.  If you |  | ||||||
|   don't have one, use a USB-to-Ethernet adapter. (A2SERVER won't work over |  | ||||||
|   Wi-Fi when running in a VM.) |  | ||||||
|  |  | ||||||
| * Optional but recommended: Under Advanced, change the MAC Address to |  | ||||||
|   080003F2FF59. |  | ||||||
|  |  | ||||||
| * Click OK. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://www.virtualbox.org/ |  | ||||||
| [2]: http://www.parallels.com/ |  | ||||||
| [3]: http://www.vmware.com/ |  | ||||||
| [4]: https://www.virtualbox.org/wiki/Downloads/ |  | ||||||
| [5]: http://www.ubuntu.com/download/server/ |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| So you got a [Raspberry Pi][1]. Congratulations! |  | ||||||
|  Are you ready to turn it into a file server for your Apple II? Here's how. |  | ||||||
|  |  | ||||||
| <!-- |  | ||||||
| *Important: As of 11-Aug-14, A2SERVER 1.2.0 is now compatible with the latest |  | ||||||
| version of Raspbian (NOOBS 1.3.9/2014-Jun-20), and the Raspberry Pi Model B+. |  | ||||||
| Type `a2server-setup` to update. If you are already running A2SERVER, and it |  | ||||||
| stopped working after a Raspbian update, see the |  | ||||||
| [recovery page](a2server_recovery.md).* |  | ||||||
| --> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Starting fresh: |  | ||||||
|  |  | ||||||
| If you haven't already started working with a Raspberry Pi, then [download |  | ||||||
| Raspple II][2], a distribution of the Raspbian operating system which includes |  | ||||||
| A2SERVER, [A2CLOUD][3], and David Schmenk's [Apple II Pi][4]. |  | ||||||
|  |  | ||||||
| Expand the RasppleII.zip file, and copy all of its files to a 4 GB or larger |  | ||||||
| SD card. Then put the SD card in your Pi, and attach power. The operating |  | ||||||
| system will automatically install, which will take about 20 minutes. |  | ||||||
|  |  | ||||||
| When it's done, your Pi will reboot into Raspbian. If you don't have a |  | ||||||
| screen attached, you'll know when it's done when the ACT/OK lamp on the |  | ||||||
| Raspberry Pi board stops flickering. |  | ||||||
|  |  | ||||||
| (If you are starting over with the same SD card, or want to ensure the card is |  | ||||||
| formatted correctly, you can use the official [SD Formatter][5] utility -- |  | ||||||
| carefully! -- before copying the files.) |  | ||||||
|  |  | ||||||
| If you wish to log in (you don't need to to use A2SERVER), the username is |  | ||||||
| "pi" and password "apple2". (If you do not have a screen and keyboard |  | ||||||
| attached to your Raspberry Pi, read about [logging into a Raspberry Pi from |  | ||||||
| another computer](a2server_raspberrypi_login.md), including an Apple II.) If |  | ||||||
| you wish to change any configuration options, type `raspi-config`. |  | ||||||
|  |  | ||||||
| For next steps, check out the links on the [A2SERVER home page](index.md). |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Already using a Raspberry Pi? |  | ||||||
|  |  | ||||||
| If you're already using Raspbian, you can install A2SERVER by typing at a |  | ||||||
| Linux prompt: |  | ||||||
|  |  | ||||||
| ~~~ bash |  | ||||||
| wget appleii.ivanx.com/a2server/setup; source setup |  | ||||||
| ~~~ |  | ||||||
|  |  | ||||||
| The process is straightforward -- just respond to the prompts. |  | ||||||
|  |  | ||||||
| For next steps, check out the links on the [A2SERVER home page](index.md). |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <!-- |  | ||||||
| (If you wish, you can read detailed technical information about the [AppleTalk |  | ||||||
| networking support on the Raspberry Pi](a2server_raspberrypi_kernel.md) that |  | ||||||
| A2SERVER installs.) |  | ||||||
| --> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://www.raspberrypi.org |  | ||||||
| [2]: http://appleii.ivanx.com/rasppleii/ |  | ||||||
| [3]: http://appleii.ivanx.com/a2cloud |  | ||||||
| [4]: http://schmenk.is-a-geek.com/wordpress |  | ||||||
| [5]: https://www.sdcard.org/downloads/formatter_4/ |  | ||||||
| @@ -1,56 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| You need to access the Raspberry Pi's command prompt in order set up A2SERVER |  | ||||||
| for network boot, and [do other stuff](a2server_commands.md). |  | ||||||
|  |  | ||||||
| The default username is "pi" and default password is "apple2". If you |  | ||||||
| don't have a screen and keyboard attached, you can: |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Log in via SSH from another computer |  | ||||||
|  |  | ||||||
| On a Mac, open Terminal (in the Utilities folder of the Applications folder), |  | ||||||
| and type `ssh pi@raspberrypi.local` to connect. If you have Windows, you can |  | ||||||
| install [Bonjour Print Services][1], and then use [PuTTY][2] to connect to the |  | ||||||
| address "raspberrypi.local". |  | ||||||
|  |  | ||||||
| If that doesn't work, or you don't want to install Bonjour Print Services |  | ||||||
| for Windows, you will need to find your Pi's IP address and use that instead. |  | ||||||
| If you have a Mac, you can use [Pi Finder][3] to help with this; if you have |  | ||||||
| Windows, you can use [Advanced IP Scanner][4]. Once logged in, you can type |  | ||||||
| `showmac` to see your Pi's MAC (Ethernet) address, and you can use this to |  | ||||||
| reserve an IP address in your router so the Pi gets the same IP address every |  | ||||||
| time. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Log in from an Apple II |  | ||||||
|  |  | ||||||
| There are a few different options for logging in from an Apple II. They are: |  | ||||||
|  |  | ||||||
| * Apple II serial: With the appropriate cables, you can use a terminal |  | ||||||
|   communications program such as [ProTERM][5], [Spectrum][6], or Z-Link |  | ||||||
|   to log into and control your Raspberry Pi. All this is set up |  | ||||||
|   automatically with [A2CLOUD][7], so head over there to read about how |  | ||||||
|   to install it and find out what cables you need to get. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| * Apple II Ethernet: If you have an [Uthernet Card][8] in an Apple IIgs, you |  | ||||||
|   can log into your Raspberry Pi with [Spectrum][6] using VT100 emulation |  | ||||||
|   (once logged in, type `TERM=vt100`). To make this work you will need to |  | ||||||
|   first log into your Pi by one of the above methods, and type `sudo apt-get |  | ||||||
|   -y install telnetd` (you may not wish to do this if your Pi is on a network |  | ||||||
|   with any untrusted users, as Telnet is unencrypted). Also, note your Pi's |  | ||||||
|   IP address (you can type `showip` once logged in) so you can provide it to |  | ||||||
|   Spectrum Internet Suite; you might want to put a DHCP reservation into your |  | ||||||
|   router (type `showmac` to get your Pi's MAC address) so you don't have to |  | ||||||
|   figure it out again. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://support.apple.com/kb/dl999 |  | ||||||
| [2]: http://www.chiark.greenend.org.uk/~sgtatham/putty/ |  | ||||||
| [3]: http://ivanx.com/raspberrypi/files/PiFinder.zip |  | ||||||
| [4]: http://www.advanced-ip-scanner.com |  | ||||||
| [5]: http://lostclassics.apple2.info/downloads/?dl_cat=11 |  | ||||||
| [6]: http://www.wannop.info/speccie/Site/Speccies_Home_Pages.html |  | ||||||
| [7]: http://appleii.ivanx.com/a2cloud/ |  | ||||||
| [8]: http://a2retrosystems.com |  | ||||||
| @@ -1,109 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| If you had A2SERVER running, and you typed either `apt-get update` or |  | ||||||
| `rpi-update`, you may have received Linux kernel version 3.12 through 3.15. |  | ||||||
| These, unfortunately, include a defective AppleTalk kernel module which will |  | ||||||
| kernel panic (crash) your system on startup when A2SERVER tries to activate |  | ||||||
| AppleTalk networking. |  | ||||||
|  |  | ||||||
| If you have a screen or console cable attached, you will see some debugging |  | ||||||
| information that concludes with "Kernel panic." If you don't have a screen |  | ||||||
| attached, there will be no visible signs other than that you simply can't |  | ||||||
| connect from another computer on your network. |  | ||||||
|  |  | ||||||
| To prevent this from happening, type `a2server-setup` *before* updating the |  | ||||||
| software on your computer. If it's too late, and you need to recover from |  | ||||||
| this situation, you could [start over][1]. Or, if you want to keep your |  | ||||||
| current installation, you have a few options, depending on your setup: |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### A2SERVER virtual machine, or on other non-Raspberry Pi Linux computer |  | ||||||
|  |  | ||||||
| * Start up the virtual or real machine. |  | ||||||
|  |  | ||||||
| * On the GRUB startup screen, choose the Recovery kernel. |  | ||||||
|  |  | ||||||
| * At the Linux prompt, type `a2server-setup` |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### A2SERVER on Raspberry Pi with screen/keyboard/mouse attached |  | ||||||
|  |  | ||||||
| * Press the shift key rapidly and repeatedly while your Pi starts up. If you |  | ||||||
|   have an HDMI monitor, you can stop when you see the installer screen. If you |  | ||||||
|   have a composite monitor, stop after about a minute, and then press 3 (PAL, |  | ||||||
|   e.g. Europe) or 4 (NTSC, e.g. North America and Japan), and you should see |  | ||||||
|   the installer screen. |  | ||||||
|  |  | ||||||
| * Press E for Edit, then click the *cmdline.txt* tab. |  | ||||||
|  |  | ||||||
| * At the end of the line, append `single` (preceded by a space). |  | ||||||
|  |  | ||||||
| * Press OK to save, then ESC to reboot. |  | ||||||
|  |  | ||||||
| * Log in with username "pi" and password "apple2". |  | ||||||
|  |  | ||||||
| * At the Linux prompt, type `a2server-setup` |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### A2SERVER on Raspberry Pi without screen/keyboard mouse, and a Mac |  | ||||||
|  |  | ||||||
| * Remove the SD card from your Pi and insert it in your Mac. |  | ||||||
|  |  | ||||||
| * Look for a volume named BOOT to appear. |  | ||||||
|  |  | ||||||
| * Within it, open *cmdline.txt* in a text editor (the default is TextEdit). |  | ||||||
|  |  | ||||||
| * At the end of the line, append `single` (preceded by a space), then save it. |  | ||||||
|  |  | ||||||
| * Eject the SD card and put it back in your Pi, then start up your Pi. |  | ||||||
|  |  | ||||||
| * [Log in to your Pi](a2server_raspberrypi_login.md) and type `a2server-setup` |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### A2SERVER on Raspberry Pi without screen/keyboard mouse, and a Linux computer |  | ||||||
|  |  | ||||||
| * Remove the SD card from your Pi. |  | ||||||
|  |  | ||||||
| * On your Linux computer, type: |  | ||||||
|    |  | ||||||
|   ~~~ bash |  | ||||||
|   wget ivanx.com/a2server/fix; source fix |  | ||||||
|   ~~~ |  | ||||||
|  |  | ||||||
| * Follow the on-screen instructions. |  | ||||||
|  |  | ||||||
| * If after using the fix tool, you still can't connect from your Apple II, |  | ||||||
|   [log in to your Pi][2], and type `a2server-setup` |  | ||||||
|  |  | ||||||
| * (Alternative approach: Follow the Mac method above, though the volume may |  | ||||||
|   not appear as BOOT.) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### A2SERVER on Raspberry Pi without screen/keyboard/mouse, and a Windows computer |  | ||||||
|  |  | ||||||
| * Remove the SD card from your Pi. |  | ||||||
|  |  | ||||||
| * Install the [A2SERVER virtual machine](a2server_virtualbox.md) on your |  | ||||||
|   Windows computer. |  | ||||||
|  |  | ||||||
| * Start the virtual machine, and log in with user name "user1" and |  | ||||||
|   password "apple2". |  | ||||||
|  |  | ||||||
| * In the virtual machine window, type: |  | ||||||
|  |  | ||||||
|   ~~~ bash |  | ||||||
|   wget ivanx.com/a2server/fix;source fix |  | ||||||
|   ~~~ |  | ||||||
|  |  | ||||||
| * Follow the on-screen instructions. |  | ||||||
|  |  | ||||||
| * Type `system-shutdown` in the virtual machine window. |  | ||||||
|  |  | ||||||
| * Quit VirtualBox. |  | ||||||
|  |  | ||||||
| * If after using the fix tool, you still can't connect from your Apple |  | ||||||
|   II, [Log in to your Pi](a2server_raspberrypi_login.md) and type |  | ||||||
|   `a2server-setup` |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://ivanx.com/a2server/ |  | ||||||
| @@ -1,123 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| When you type A2SERVER-setup, a series of scripts are downloaded from |  | ||||||
| appleii.ivanx.com and executed, some with root privileges. They are run from |  | ||||||
| the /tmp folder, and deleted upon completion. |  | ||||||
|  |  | ||||||
| Here is what they do, in the order shown (click the links to view the scripts |  | ||||||
| themselves): |  | ||||||
|  |  | ||||||
| [Master setup script](setup/index.txt) |  | ||||||
|  |  | ||||||
| * checks for supported OS and warns if it isn't |  | ||||||
|  |  | ||||||
| * offers to change user password (Raspberry Pi only) |  | ||||||
|  |  | ||||||
| * runs all of the scripts below |  | ||||||
|  |  | ||||||
| * offers to download a replacement kernel with AppleTalk support (Raspberry Pi |  | ||||||
|   only) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [Storage setup](scripts/a2server-1-storage.txt) (runs during initial setup, skipped on subsequent runs) |  | ||||||
|  |  | ||||||
| * Make the /media/A2SHARED directory |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [A2SERVER tools install](scripts/a2server-2-tools.txt) (always runs) |  | ||||||
|  |  | ||||||
| <!-- |  | ||||||
| * update package list and upgrade packages (apt-get update/upgrade) |  | ||||||
| --> |  | ||||||
|  |  | ||||||
| * download, compile, and install nulib2 (ShrinkIt archive utility), into |  | ||||||
|   /usr/local/bin |  | ||||||
|  |  | ||||||
| * install libraries required for compiling [The Unarchiver][1] |  | ||||||
|  |  | ||||||
| * download, compile, and install unar/lsar (The Unarchiver), into |  | ||||||
|   /usr/local/bin |  | ||||||
|  |  | ||||||
| * install A2SERVER tools into /usr/local/bin and /usr/local/etc: |  | ||||||
|   [afpsync](scripts/tools/afpsync.txt), |  | ||||||
|   [afptype](scripts/tools/afptype.txt), |  | ||||||
|   [cppo](scripts/tools/cppo.txt), |  | ||||||
|   [mkatinit](scripts/tools/mkatinit.txt), |  | ||||||
|   [volnifo](scripts/tools/mkvolinfo.txt), |  | ||||||
|   [aliases](scripts/tools/a2server-aliases.txt) (described at the bottom of |  | ||||||
|   [this page](a2server_commands.html)) |  | ||||||
|  |  | ||||||
| * set up aliases file to be read at each login (/etc/profile) |  | ||||||
|  |  | ||||||
| * customize pre-login message on Ubuntu (/etc/issue), or post-login message on |  | ||||||
|   non-Ubuntu (/etc/motd) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [Netatalk install and configure](scripts/a2server-3-sharing.txt) (runs during |  | ||||||
| initial setup and if upgrade to Netatalk is required; otherwise skipped) |  | ||||||
|  |  | ||||||
| * stop Netatalk service if it is running |  | ||||||
|  |  | ||||||
| * update package list and upgrade packages |  | ||||||
|  |  | ||||||
| * download and install libraries required for compiling Netatalk |  | ||||||
|  |  | ||||||
| * download Netatalk source code |  | ||||||
|  |  | ||||||
| * modify source code to make dates work correctly |  | ||||||
|  |  | ||||||
| * compile and install Netatalk |  | ||||||
|  |  | ||||||
| * set up Netatalk configuration files for Apple II use |  | ||||||
|  |  | ||||||
| * start Netatalk service |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [Network boot setup](scripts/a2server-5-netboot.txt) (always runs) |  | ||||||
|  |  | ||||||
| * ask whether user wants network boot (skips to the last step in this section |  | ||||||
|   if not) |  | ||||||
|  |  | ||||||
| * download boot blocks disk from Apple and convert it to raw block dump file |  | ||||||
|  |  | ||||||
| * copy boot blocks files and BASIC.SYSTEM |  | ||||||
|  |  | ||||||
| * use mkatinit to enable Apple II network boot |  | ||||||
|  |  | ||||||
| * patch boot block files to support cleartext passwords, and typing "8" |  | ||||||
|   during IIGS network startup to force ProDOS 8 boot |  | ||||||
|  |  | ||||||
| * ask user whether to download and install GS/OS |  | ||||||
|  |  | ||||||
| * ask whether user wants to download disk image and file utilities |  | ||||||
|  |  | ||||||
| * ask whether user wants to install Farallon bridge patch |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [Windows file sharing](scripts/a2server-6-samba.txt) (always runs) |  | ||||||
|  |  | ||||||
| * ask whether user wants Windows file sharing, and if so: |  | ||||||
|  |  | ||||||
| * download and install samba, and start the service |  | ||||||
|  |  | ||||||
| * set up samba configuration files |  | ||||||
|  |  | ||||||
| * if user doesn't want Windows file sharing, stop the samba service |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [Console optimizing](scripts/a2server-7-console.txt) (runs during initial |  | ||||||
| setup, skipped on subsequent runs) |  | ||||||
|  |  | ||||||
| * disable default Ubuntu Server login message |  | ||||||
|  |  | ||||||
| * make console clear boot messages before initial login prompt |  | ||||||
|  |  | ||||||
| * eliminate piix4\_smbus error message before initial login prompt |  | ||||||
|  |  | ||||||
| * prevent console from going blank after ten minutes of inactivity (after |  | ||||||
|   login) |  | ||||||
|  |  | ||||||
| * resolve a slow-scrolling problem in Ubuntu Server 10.04 (only) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://wakaba.c3.cx/s/apps/unarchiver.html |  | ||||||
| @@ -1,234 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
|  |  | ||||||
| The A2SERVER Odyssey |  | ||||||
|  |  | ||||||
| A2SERVER has been a multi-year labor of love. |  | ||||||
|  |  | ||||||
| Way back in 2010, my primary Apple II was a Mac Color Classic with an Apple |  | ||||||
| IIe compatibility card. |  | ||||||
|  |  | ||||||
| One of the things this card could do was emulate something called a |  | ||||||
| Workstation Card, which appeared to let Apple II computers access files on a |  | ||||||
| Mac file server. This was intriguing; I hadn't imagined it was possible. |  | ||||||
|  |  | ||||||
| And it was also potentially valuable as a way of providing mass storage for an |  | ||||||
| Apple II, with the bonus that other computers could easily access it as a |  | ||||||
| means of getting stuff to and from an otherwise isolated machine. |  | ||||||
|  |  | ||||||
| After some experimenting, I discovered that was exactly what it did, and I |  | ||||||
| bought an actual Workstation Card for my IIe, because that would be much, much |  | ||||||
| cooler. And it appeared that you could even *boot* the Apple II into ProDOS |  | ||||||
| from the network, which blew my mind. Using AppleShare 3.0 on another Mac as a |  | ||||||
| host, I made this happen, and there was much rejoicing. |  | ||||||
|  |  | ||||||
| Then, I got an idea into my head: this is great and everything, but you still |  | ||||||
| need an old Mac around. How great would it be if you could just have an |  | ||||||
| always-on network drive for an Apple II, with all the storage you might ever |  | ||||||
| need, and accessible from other computers on the LAN? |  | ||||||
|  |  | ||||||
| (It's true that there were Compact Flash storage cards at the time, and I |  | ||||||
| actually bought CFFA #16, but these didn't appeal to me quite as much because |  | ||||||
| of their relative lack of accessibility on other platforms. I'd need some |  | ||||||
| sort of CF extender to get the card outside the machine, then run CiderPress |  | ||||||
| in a Windows emulator...) |  | ||||||
|  |  | ||||||
| It so happens that I had purchased a Western Digital My Book World Edition, |  | ||||||
| which was one of the first popular NAS products available. It was basically a |  | ||||||
| small Linux computer in a drive enclosure, and it was widely hacked to make it |  | ||||||
| do all kinds of tricks, one of which was providing native file sharing for |  | ||||||
| Macs. |  | ||||||
|  |  | ||||||
| This was possible by installing Netatalk, an open-source implentation of AFP |  | ||||||
| (AppleShare). I immediately wondered if it would be possible to somehow get my |  | ||||||
| IIe to talk to it. So I looked into it, and it appeared that Netatalk running |  | ||||||
| on Linux still supported the older AppleTalk networking protocol required by |  | ||||||
| an Apple II, and it even supported network boot into ProDOS. |  | ||||||
|  |  | ||||||
| There was the issue of how to actually interface my Apple II to the network; |  | ||||||
| this turned out to be relatively easy, by using an Apple-provide control panel |  | ||||||
| for classic Macs called LocalTalk Bridge, which indeed bridged AppleTalk from |  | ||||||
| its LocalTalk port (connected to an Apple II) to its Ethernet port (connected |  | ||||||
| to my network, which was connected to the NAS). But this was clumsy, so I |  | ||||||
| invested in an AsanteTalk, which is a dedicated (if finicky) |  | ||||||
| LocalTalk-to-Ethernet bridge. |  | ||||||
|  |  | ||||||
| What I discovered, after some time, was that a) the version of Linux that |  | ||||||
| shipped on that NAS did not include support for AppleTalk networking, and b) |  | ||||||
| the easily-installed Netatalk package didn't include the components required |  | ||||||
| for network boot, which I absolutely wanted. |  | ||||||
|  |  | ||||||
| I wasn't terribly Linux-savvy at the time, but I eventually figured out that |  | ||||||
| to get network boot support, I would need to download Netatalk and compile it |  | ||||||
| myself, from source. Ok. But once I learned that adding AppleTalk support |  | ||||||
| overall would require recompiling a kernel for the drive, I kind of put the |  | ||||||
| idea aside, figuring I'd bring it to KFest and hack on it with someone there |  | ||||||
| who knows what they're doing. |  | ||||||
|  |  | ||||||
| In the meantime, I decided to see if I could make things work exactly as I |  | ||||||
| wanted with a "proper" Linux installation. Ubuntu Linux was well-known for |  | ||||||
| its relative ease of use, so I installed that into VMWare Fusion running on my |  | ||||||
| (modern) Mac. I installed the Netatalk package, and that worked -- though it |  | ||||||
| was still missing the network boot component, and there were other issues like |  | ||||||
| password login not working correctly. |  | ||||||
|  |  | ||||||
| So I had to figure out how to recompile Netatalk to make it do what I needed. |  | ||||||
| I managed to figure this out after much effort and studying of posts and |  | ||||||
| contributions to comp.sys.apple2, but wasn't able to get it to actually |  | ||||||
| netboot to ProDOS. |  | ||||||
|  |  | ||||||
| So this led me to comp.sys.apple2, and there met two people who turned out to |  | ||||||
| be two enormous contributors to A2SERVER: Steven Hirsch, who wrote much of the |  | ||||||
| actual network boot support in Netatalk, and Geoff Body, who knows everything |  | ||||||
| about the "boot blocks" that get transferred to the Apple IIe or IIgs during |  | ||||||
| network startup. Both Steven and Geoff have also helped figure out and work |  | ||||||
| around the idiosyncracies of many of the dedicated LocalTalk-to-Ethernet |  | ||||||
| bridges, and have been essential contributors to the execution of A2SERVER. |  | ||||||
|  |  | ||||||
| The initial conversation is chronicled in perpetuity here: |  | ||||||
| https://groups.google.com/forum/#!topic/comp.sys.apple2/b\_TzESci6Kg |  | ||||||
|  |  | ||||||
| With their help, I finally succeeded in network booting my Apple IIe from my |  | ||||||
| Linux virtual machine. The first proto-version of A2SERVER was a step-by-step |  | ||||||
| guide to manually set it up, as posted here: |  | ||||||
| https://groups.google.com/forum/#!topic/comp.sys.apple2/lkh4hXqmJbE |  | ||||||
|  |  | ||||||
| I could have left it at that, but I didn't like it. It wasn't all THAT easy |  | ||||||
| for a non-Linux person, network boot relied on Apple software from a "secret |  | ||||||
| archive" and hand-hacked binary code from within the guide itself, and the |  | ||||||
| final setup was hard-coded to a specific user name. I wanted a version that |  | ||||||
| was general-purpose, easy for anyone to install, and which obtained any |  | ||||||
| copyrighted software from 100% public, authorized sources. |  | ||||||
|  |  | ||||||
| And which, in a perfect world, could be configured to netboot from "bare |  | ||||||
| metal" -- that is, a bare computer with nothing but Linux would be able to |  | ||||||
| boot an Apple IIe or IIgs with no operating system, software, or even any |  | ||||||
| drives at all. |  | ||||||
|  |  | ||||||
| I hadn't forgotten about wanting it to run on a NAS, either, but I figured |  | ||||||
| I'd circle back to that, since it was so much easier working in a VM. For the |  | ||||||
| time being, what I'd ship would be both a premade VM, and a complete |  | ||||||
| installer script for actual Linux installations. And that would be A2SERVER. |  | ||||||
|  |  | ||||||
| Then it was a matter of locating what I could, from anyone I could, to make it |  | ||||||
| work. I discovered that the boot blocks and BASIC.SYSTEM -- the essential |  | ||||||
| pieces for netbooting ProDOS 8 -- were ensconced with the GSOS "Disk 7" |  | ||||||
| image available from Apple's Older Software downloads page. But that disk |  | ||||||
| image was a DiskDoubler self-extracting archive. Fortunately, The Unarchiver |  | ||||||
| could uncompress it, and is open-source, and builds on Linux. The disk image |  | ||||||
| was actually an HFS disk, which Linux has support for, so I was able to mount |  | ||||||
| it and copy the files out. |  | ||||||
|  |  | ||||||
| Steven contributed a huge fix to the Netatalk source code so ProDOS dates get |  | ||||||
| handled correctly. Geoff gave me patches to the Boot Blocks to fix a cleartext |  | ||||||
| login bug and allow an on-demand startup option to boot into ProDOS 8 on a |  | ||||||
| IIgs. |  | ||||||
|  |  | ||||||
| Then I had to hack a bunch of stuff together. I wrote mkatinit to create the |  | ||||||
| very specific user login files required for netboot; afpsync to simplify |  | ||||||
| Netatalk's handling of new shared files introduced from Linux; afptype to |  | ||||||
| allow setting the ProDOS (or classic Mac) file type of a file shared by |  | ||||||
| Netatalk. |  | ||||||
|  |  | ||||||
| These tools, plus a properly-compiled-and-configured Netatalk, made it |  | ||||||
| possible for a Linux server to entirely download ProDOS 8 and set it up for |  | ||||||
| network boot by an Apple II. Nothing had to be done on the Apple II side. Bare |  | ||||||
| metal! |  | ||||||
|  |  | ||||||
| I then shaped my guide into an actual executable script which could be |  | ||||||
| downloaded from my web site and executed on any Ubuntu installation. I |  | ||||||
| expanded the script to download and install the necessary tools, apply the |  | ||||||
| necessary patches, and everything else I felt was needed for click-and-go |  | ||||||
| server Apple II server setup, such as optional Windows file sharing (since one |  | ||||||
| of the goals was easy file interchange with modern computers). |  | ||||||
|  |  | ||||||
| And that was kinda that -- almost. I'd conquered the IIe, but the real Mt. |  | ||||||
| Everest was bare metal GS/OS netboot. This was much more challenging: it meant |  | ||||||
| I'd have to get the files out of the ProDOS-formatted GSOS installer disk |  | ||||||
| images, with resource forks intact and made usable by Netatalk. This is what I |  | ||||||
| wanted to show off when I introduced A2SERVER at KansasFest 2011. |  | ||||||
|  |  | ||||||
| There was no off-the-shelf solution for this, so I spent pretty much every |  | ||||||
| waking hour in Kansas City furiously creating cppo, which would copy files out |  | ||||||
| of a ProDOS disk image. And...I failed. I just ran out of time before my |  | ||||||
| presentation. |  | ||||||
|  |  | ||||||
| So I installed a Network Startup instalation of GS/OS the conventional way -- |  | ||||||
| using the IIgs installer disks running on a IIgs, with the Netatalk shared |  | ||||||
| volume as the target. (The CFFA3000, which was also introduced that same |  | ||||||
| KansasFest, was absolutely invaluable for this.) |  | ||||||
|  |  | ||||||
| And it worked. In my presentation, I was able to network boot Peter |  | ||||||
| Neubauer's Apple IIe with nothing but the Workstation Card; and my IIgs with |  | ||||||
| nothing but a RAM card. |  | ||||||
|  |  | ||||||
| Then I came back home. I completed cppo, and it worked, mostly; with that |  | ||||||
| done, I then set about writing something to interpret the GS/OS installer |  | ||||||
| scripts and cppo the right pieces to the right places. And...it worked too. |  | ||||||
| Except that it didn't. It all started up, but the Finder had random |  | ||||||
| filenames, the Trash was full when there was nothing in it. It was corrupt. |  | ||||||
| Who knows why. I gave up. |  | ||||||
|  |  | ||||||
| I wasn't satisfied with not being able to start up a IIgs at all if you |  | ||||||
| didn't have the installer disks; so I made it netboot into ProDOS 8, from |  | ||||||
| where you could use DSK2FILE (which the A2SERVER installer script offers to |  | ||||||
| download) to convert the disk images to actual disks, which you could then use |  | ||||||
| to make an AppleShare startup floppy, which you could THEN use to mount the |  | ||||||
| shared volume and use it as a target for a full Network Startup install. Icky, |  | ||||||
| and of possible benefit to no one (really, who doesn't have GS/OS install |  | ||||||
| disks and a drive?), but it was some kind of solution. I packaged up the VM, |  | ||||||
| put up these web pages, and decided it was Done. |  | ||||||
|  |  | ||||||
| But the NAS thing itched at me. I wanted to be able to suggest an easily |  | ||||||
| obtained product. By now, WD had replaced my NAS with the My Book Live, which |  | ||||||
| featured a much faster processor, and was based on Debian Linux, which is what |  | ||||||
| Ubuntu is derived from. This was a promising starting point. I figured out how |  | ||||||
| to compile an AppleTalk kernel module for it. And then I already had these |  | ||||||
| turnkey scripts ready to go, so I hacked, and hacked, and...I couldn't get it |  | ||||||
| to work. I'd sometimes get gibberish for volume names, and network boot would |  | ||||||
| load the boot blocks, and then never stop loading, filling the Apple II's |  | ||||||
| memory with zeroes until it crashed. (My suspicion is that the big-endianness |  | ||||||
| of the PowerPC CPU in the newer NAS may have been a factor.) Fixing that would |  | ||||||
| have taken me deep into the packetized heart of Netatalk, which is beyond my |  | ||||||
| pay grade. I gave up, and decided A2SERVER was Done. Again. |  | ||||||
|  |  | ||||||
| Until I went to KansasFest 2012, and Eric Rucker showed me something I had |  | ||||||
| never heard of: a Raspberry Pi. Somewhere, the gears started turning, and |  | ||||||
| months later I checked it out, and saw that its primary operating system |  | ||||||
| was...a Debian derivative. Could this be my long-sought-after NAS? |  | ||||||
|  |  | ||||||
| It was. The install scripts ran with only a little tweaking. I did have to |  | ||||||
| compile AppleTalk in the kernel, but eventually I had what I wanted. And it |  | ||||||
| was only $35! |  | ||||||
|  |  | ||||||
| I revisited the corrupted GS/OS installation. I couldn't put my finger on |  | ||||||
| what was wrong. But I noticed that the Finder showed a different length on its |  | ||||||
| source disk and after copying. So I followed its index blocks, and discovered |  | ||||||
| that contained in those were 0000's. ProDOS knew to fill blocks with zeros, |  | ||||||
| but cppo was dutifully copying Block 0, the ProDOS boot block, thereby |  | ||||||
| corrupting the Finder. I fixed this, and then I HAD IT: Bare metal install |  | ||||||
| GS/OS from Linux. Yeah, man. |  | ||||||
|  |  | ||||||
| And, so, then it was just tweaking and refining and tweaking and refining. The |  | ||||||
| big bummer as far as general use goes was that all the common |  | ||||||
| LocalTalk-to-Ethernet bridges (Dayna, AsanteTalk, and Farallon) were partially |  | ||||||
| or completely inoperable with a IIgs, and the Workstation Card required for a |  | ||||||
| IIe is hardly in great abundance. But Geoff Body came up with a fix for the |  | ||||||
| Farallon, I came up with a workaround for the AsanteTalk, and Steven Hirsch |  | ||||||
| came up with an actual fix for both the AsanteTalk and the Dayna, meaning |  | ||||||
| *all* of those bridges are now options for a IIgs owner! |  | ||||||
|  |  | ||||||
| So this was it: bare IIgs (even without memory card, if you're OK with ProDOS |  | ||||||
| 8) + Raspberry Pi + readily available bridge = Apple II file server. Yeah! |  | ||||||
|  |  | ||||||
| And I discovered that with a USB cable or RPi console cable, you could |  | ||||||
| actually log in and control it with ProTERM. With Hugh Hood's clever ProTERM |  | ||||||
| patch for 115,200 bps on a IIgs, I could actually see my Raspberry Pi start |  | ||||||
| up...on my Apple II. I can't explain how joyous this made me. |  | ||||||
|  |  | ||||||
| And, I wrote ProDOS 8 utilities to switch the IIgs boot mode, which is |  | ||||||
| normally only possible under GS/OS. |  | ||||||
|  |  | ||||||
| I could go on and on, but basically the ideas kept coming, and I think I was |  | ||||||
| able I was able to polish most of A2SERVER's rough edges so that it could be |  | ||||||
| fun and/or useful for a few people. I hope you enjoy it! |  | ||||||
| @@ -1,44 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
|  |  | ||||||
| To set up A2SERVER, follow these steps: |  | ||||||
|  |  | ||||||
| * Download and install [VirtualBox][1]. It's free. (If you prefer different |  | ||||||
|   virtual machine software, [you can instead use the A2SERVER installer |  | ||||||
|   script](a2server_installer.md).) |  | ||||||
|  |  | ||||||
| * Download the [A2SERVER virtual machine](files/A2SERVER.ova) (~750 MB), or |  | ||||||
|   the [A2SERVER+A2CLOUD virtual machine](files/A2SERVER_A2CLOUD.ova) (~1.7 |  | ||||||
|   GB). |  | ||||||
|  |  | ||||||
| * Open VirtualBox, and choose "Import Appliance..." from the File menu. |  | ||||||
|   Select the file you downloaded (A2SERVER.ova). |  | ||||||
|  |  | ||||||
| * Leave the "Reinitialize the MAC address of all network cards" box |  | ||||||
|   unchecked. Click Import. |  | ||||||
|  |  | ||||||
| * When it's done importing, click A2SERVER, then click Settings, then click |  | ||||||
|   Network. |  | ||||||
|  |  | ||||||
| * Ensure that "Attached To:" is set to "Bridged Adapter". |  | ||||||
|  |  | ||||||
| * Set "Name:" to a _wired_ network interface on your computer. If you don't |  | ||||||
|   have one, use a USB-to-Ethernet adapter. (A2SERVER won't work over Wi-Fi in |  | ||||||
|   a virtual machine.) |  | ||||||
|  |  | ||||||
| * Click OK. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| You're all set up. For next steps, check out the links on the [A2SERVER home |  | ||||||
| page](index.md). |  | ||||||
|  |  | ||||||
|  |  | ||||||
| SHA-1 for A2SERVER VM: d6c60b0ab14f14ddd49b7e5cdac39503db96a903  |  | ||||||
| SHA-1 for A2SERVER+A2CLOUD VM: 69df7c28fa21e4e4cc01b106398936f23559a64b  |  | ||||||
| <!-- |  | ||||||
| v1.1.3: a8927d6fba9dfa9c2015918cdc61122bb2c95ea5  |  | ||||||
| v1.1.0: 63eebfcfe9fbbeb17aa4ab3226e849289072d396 |  | ||||||
| --> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: https://www.virtualbox.org/wiki/Downloads |  | ||||||
| @@ -1,78 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| While wired Ethernet is recommended, it's possible to use A2SERVER with Wi-Fi |  | ||||||
| if you have an Apple AirPort or Time Capsule. (A2SERVER won't work with most |  | ||||||
| non-Apple router and access point models, as they are not designed to handle |  | ||||||
| AppleTalk networking.) |  | ||||||
|  |  | ||||||
| To connect your Apple II via Wi-Fi, read how to [attach your Apple II to your |  | ||||||
| local network](a2server_lan.md). |  | ||||||
|  |  | ||||||
| If you want your A2SERVER machine (whether virtual, real, or Raspberry Pi) to |  | ||||||
| connect to your network via Wi-Fi, you first need to configure a Wi-Fi network |  | ||||||
| adapter via the instructions below. Once you've got that up and running, [log |  | ||||||
| in](a2server_commands.md) to A2SERVER and type `netatalk-wifi` to tell |  | ||||||
| A2SERVER to use the Wi-Fi interface (if you get "command not found", type |  | ||||||
| `a2server-setup` to refresh the command list). |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Setting up Wi-Fi on your A2SERVER machine: |  | ||||||
|  |  | ||||||
| ### Multiple AirPorts |  | ||||||
|  |  | ||||||
| As an alternative to using a Wi-Fi network adapter, any of the machine types |  | ||||||
| below can work with Wi-Fi simply by connecting the wired Ethernet interface to |  | ||||||
| another AirPort and setting up an [extended network][1] (if all AirPorts are |  | ||||||
| 802.11n models), or a [WDS][2] (if any AirPort is an 802.11g model). |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Raspberry Pi |  | ||||||
|  |  | ||||||
| [We got a whole page about that.][3] |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Virtual machine |  | ||||||
|  |  | ||||||
| On a virtual machine, A2SERVER won't work over Wi-Fi with the virtual network |  | ||||||
| interface, but you may, or may not, be able to use a USB Wi-Fi adapter |  | ||||||
| attached your VM's emulated USB port, and then follow the instructions below |  | ||||||
| for a real machine. Some adapters may have issues with specific virtual |  | ||||||
| machine software; for example, Atheros 9K based adapters [do not work with |  | ||||||
| VirtualBox][4] or VMWare Fusion, though they do work with Parallels Desktop; |  | ||||||
| Realtek 81xx based adapters seem to work with VirtualBox (at minimum). |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Real machine (Intel or compatible) |  | ||||||
|  |  | ||||||
| On a standard computer with a native Linux installation, if you can get a |  | ||||||
| Wi-Fi adapter working, it will probably work with A2SERVER. Instructions will |  | ||||||
| vary by distribution, but should be similar to [the guide for Raspberry |  | ||||||
| Pi][3], with a much wider range of usable adapters. |  | ||||||
|  |  | ||||||
| If those steps don't work, type `sudo nano /etc/network/interfaces`, and edit |  | ||||||
| the file so it contains a sequence of lines that look like this: |  | ||||||
| `allow-hotplug wlan0 iface wlan0 inet dhcp wpa-ssid MyNetworkName` (substitute |  | ||||||
| your Wi-Fi network name) `wpa-psk abcdefgh` (substitute your WPA password, or |  | ||||||
| its 64-character hex equivalent) |  | ||||||
|  |  | ||||||
| If you are using WEP encryption instead of WPA, replace the last two lines |  | ||||||
| with:  |  | ||||||
| `wireless-essid MyNetworkName` (substitute your Wi-Fi network name)  |  | ||||||
| `wireless-key abcde` (substitute your 5 or 13 character, or 10 or 26 hex byte,  |  | ||||||
| WEP password) |  | ||||||
|  |  | ||||||
| Spaces in the Wi-Fi network name or password may not work. |  | ||||||
|  |  | ||||||
| Remove any other chunks which mention wlan0, and save the file (press |  | ||||||
| control-w). Then type: `sudo ifdown wlan0; sudo ifup wlan0` |  | ||||||
|  |  | ||||||
| Finally, type `ip addr`. If you see an IP address for wlan0 (next to |  | ||||||
| "inet"), your Wi-Fi adapter is on your network, and you can disconnect your |  | ||||||
| Ethernet or serial cable. (If you don't seem to have internet access, type |  | ||||||
| `sudo shutdown -r now` to restart.) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://support.apple.com/kb/HT4259 |  | ||||||
| [2]: http://support.apple.com/kb/HT4262 |  | ||||||
| [3]: http://ivanx.com/raspberrypi/raspberrypi_wifi.html |  | ||||||
| [4]: https://www.virtualbox.org/ticket/9511 |  | ||||||
| @@ -1,91 +0,0 @@ | |||||||
| ## A2SERVER |  | ||||||
|  |  | ||||||
| A2SERVER lets you use a [Raspberry Pi][1], or almost any other computer, to |  | ||||||
| serve files to Apple IIgs and enhanced IIe computers on your network. You'll |  | ||||||
| also be able to boot into GS/OS or ProDOS 8 directly from tne network (no |  | ||||||
| drives needed). A2SERVER has been designed to be as easy to set up and use as |  | ||||||
| possible, and it's free. |  | ||||||
|  |  | ||||||
| <!-- |  | ||||||
| A2SERVER is available as a Raspberry Pi installer, or a virtual machine which |  | ||||||
| runs on Mac OS X, Windows, Linux, or Solaris computers, or as an easy-to-use |  | ||||||
| installer for Ubuntu or Debian Linux. |  | ||||||
| --> |  | ||||||
|  |  | ||||||
|  A2SERVER is based on open-source software, primarily [Netatalk][2] 2.2.4, |  | ||||||
|  with [many utilities and enhancements](a2server_features.md) to make |  | ||||||
|  everything as easy as possible. (If you like A2SERVER, you might also want to |  | ||||||
|  check out [A2CLOUD][3].) |  | ||||||
|  |  | ||||||
| <!-- |  | ||||||
| If you haven't checked out A2SERVER in a while: it now runs on something |  | ||||||
| small, cheap, and silent, and every common LocalTalk-to-Ethernet bridge now |  | ||||||
| works easily with a IIgs (as opposed to none previously). And A2SERVER |  | ||||||
| supports Wi-Fi, and can download and install GS/OS on your network drive for |  | ||||||
| you. Cool stuff! |  | ||||||
| --> |  | ||||||
|  |  | ||||||
| *Update 19-Mar-15: A2SERVER 1.2.2 is available. It has support for Raspberry |  | ||||||
| Pi 2 Model B and every other Raspberry Pi, and new command line options for |  | ||||||
| the installer script. To update, type `a2server-setup`.* |  | ||||||
|  |  | ||||||
| Choose how you'd like to use A2SERVER, and you'll be up and running shortly. |  | ||||||
|  |  | ||||||
|  * [Raspberry Pi](a2server_raspberrypi.md) |  | ||||||
|  * [Virtual Machine](a2server_virtualbox.md) (for Mac OS X, Windows, Linux, |  | ||||||
|    Solaris) |  | ||||||
|  * [Installer for Ubuntu or Debian Linux](a2server_installer.md) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Once you've got it set up, here are next steps: |  | ||||||
|  |  | ||||||
| [Attach your Apple II to your local network](a2server_lan.md) |  | ||||||
|  |  | ||||||
| [Connect to A2SERVER from your Apple II](a2server_howtouse.md) |  | ||||||
|  |  | ||||||
| [Boot into ProDOS 8 or GS/OS over the network](a2server_netboot.md) |  | ||||||
|  |  | ||||||
| [Log into, shut down, and do stuff in the A2SERVER |  | ||||||
| console](a2server_commands.md) |  | ||||||
|  |  | ||||||
| [Access A2SERVER files from a Mac or Windows computer](a2server_access.md) |  | ||||||
|  |  | ||||||
| [Use A2SERVER with Wi-Fi](a2server_wifi.md) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| And some other stuff that might (or might not) be helpful or interesting: |  | ||||||
|  |  | ||||||
| [A2SERVER feature list](a2server_features.md) |  | ||||||
|  |  | ||||||
| [A2SERVER version history](update/versionhistory.txt) |  | ||||||
|  |  | ||||||
| [Recover from a crashed A2SERVER](a2server_recovery.md) |  | ||||||
|  |  | ||||||
| [Details of what the "a2server-setup" script |  | ||||||
| does](a2server_scriptdetails.md) |  | ||||||
|  |  | ||||||
| [See the March 2013 cover of Juiced.GS][4], featuring A2SERVER |  | ||||||
|  |  | ||||||
| [Watch me introduce A2SERVER at KansasFest 2011][5] (note: this contains some |  | ||||||
| outdated information) |  | ||||||
|  |  | ||||||
| [The A2SERVER odyssey](a2server_story.md) (warning: long) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Buckets of thanks to Steven Hirsch and Geoff Body, whose invaluable assistance |  | ||||||
| and contributions have made A2SERVER exist, along with Tony Diaz, Antoine |  | ||||||
| Vignau, Peter Wong, Martin Haye, Ken Gagne, Peter Neubauer, Anthony Martino, |  | ||||||
| James Littlejohn, and others at comp.sys.apple2 and KansasFest. (As well as |  | ||||||
| the creators, past and present, of Netatalk and Raspberry Pi.) Apple II |  | ||||||
| Forever! |  | ||||||
|  |  | ||||||
| Questions? Comments? email [ivan@ivanx.com](mailto:ivan@ivanx.com) |  | ||||||
|  |  | ||||||
| [Apple II Extravaganza home page](http://appleii.ivanx.com/) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| [1]: http://www.raspberrypi.org |  | ||||||
| [2]: http://netatalk.sourceforge.net |  | ||||||
| [3]: http://ivanx.com/a2cloud |  | ||||||
| [4]: http://juiced.gs/2013/03/v18i1-now-shipping/ |  | ||||||
| [5]: http://www.youtube.com/watch?v=w88NjWRK7Kk |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # --- Setting up the share volume |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # skip if we're already set up |  | ||||||
| if [[ -d /media/A2SHARED ]]; then |  | ||||||
|  |  | ||||||
|     echo "A2SERVER: Shared disk is already prepared for use." |  | ||||||
|      |  | ||||||
| else |  | ||||||
|      |  | ||||||
|     echo "A2SERVER: Preparing the shared files disk..." |  | ||||||
|      |  | ||||||
|     sudo mkdir /media/A2SHARED |  | ||||||
|      |  | ||||||
|     sudo chown $USER:$USER /media/A2SHARED |  | ||||||
|  |  | ||||||
| fi |  | ||||||
| @@ -1,126 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # download and install a2server tools: |  | ||||||
| # mkatinit, mkvolinfo, afptype, afpsync, aliases, nulib2 |  | ||||||
|  |  | ||||||
| isRpi= |  | ||||||
| [[ -f /usr/bin/raspi-config ]] && isRpi=1 |  | ||||||
|  |  | ||||||
| isDebian= |  | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1-2 < /etc/debian_version) == "7." ) && ( $(uname -m) == "i686" ) ]] && isDebian=1 |  | ||||||
|  |  | ||||||
| echo "A2SERVER: Installing A2SERVER tools..." |  | ||||||
|  |  | ||||||
| if [[ ! -f /usr/local/bin/nulib2 ]]; then |  | ||||||
|  |  | ||||||
|     echo "A2SERVER: Installing nulib2..." |  | ||||||
|  |  | ||||||
|     cd /tmp |  | ||||||
|     if [[ $isRpi ]]; then |  | ||||||
|         wget -qO- ivanx.com/a2server/files/nulib2-rpi.tgz | sudo tar Pzx |  | ||||||
|     elif [[ $isDebian ]]; then |  | ||||||
|         wget -qO- ivanx.com/a2server/files/nulib2-debian7_x86.tgz | sudo tar Pzx |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     if [[ ! -f /usr/local/bin/nulib2 ]]; then |  | ||||||
|  |  | ||||||
|         if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then |  | ||||||
|             # prepare for installing packages |  | ||||||
|             sudo apt-get -y update |  | ||||||
|             touch /tmp/a2server-packageReposUpdated |  | ||||||
|         fi |  | ||||||
|  |  | ||||||
|         sudo apt-get -y install build-essential |  | ||||||
|         sudo apt-get -y install zlib1g-dev |  | ||||||
|         sudo apt-get -y clean |  | ||||||
|         cd /tmp |  | ||||||
|         rm -rf /tmp/nulib &> /dev/null |  | ||||||
|         mkdir /tmp/nulib |  | ||||||
|         cd /tmp/nulib |  | ||||||
|         wget -q -O nulib.tgz http://web.archive.org/web/20131031160750/http://www.nulib.com/downloads/nulibdist.tar.gz |  | ||||||
|         tar zxf nulib.tgz |  | ||||||
|         cd nufxlib* |  | ||||||
|         ./configure |  | ||||||
|         make |  | ||||||
|         sudo make install |  | ||||||
|         cd ../nulib2* |  | ||||||
|         ./configure |  | ||||||
|         make |  | ||||||
|         sudo make install |  | ||||||
|         cd |  | ||||||
|         rm -rf /tmp/nulib |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
| else |  | ||||||
|     echo "A2SERVER: Nulib2 has already been installed." |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # download and install The Unarchiver, for expanding Apple disk images |  | ||||||
| # http://wakaba.c3.cx/s/apps/unarchiver.html |  | ||||||
|  |  | ||||||
| if [[ ! -f /usr/local/bin/unar ]]; then |  | ||||||
|  |  | ||||||
|     echo "A2SERVER: Installing The Unarchiver..." |  | ||||||
|  |  | ||||||
|     if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then |  | ||||||
|         # prepare for installing packages |  | ||||||
|         sudo apt-get -y update |  | ||||||
|         touch /tmp/a2server-packageReposUpdated |  | ||||||
|     fi |  | ||||||
|      |  | ||||||
|     if [[ $isRpi || $isDebian ]]; then |  | ||||||
|         sudo apt-get -y install libgnustep-base1.22 |  | ||||||
|         sudo apt-get clean |  | ||||||
|         if [[ $isRpi ]]; then |  | ||||||
|             wget -qO- ivanx.com/a2server/files/unar-rpi.tgz | sudo tar Pzx |  | ||||||
|         elif [[ $isDebian ]]; then |  | ||||||
|             wget -qO- ivanx.com/a2server/files/unar-debian7_x86.tgz | sudo tar Pzx |  | ||||||
|         fi |  | ||||||
|     fi |  | ||||||
|     if [[ ! -f /usr/local/bin/unar ]]; then |  | ||||||
|         sudo apt-get -y install build-essential |  | ||||||
|         sudo apt-get -y install libgnustep-base-dev libz-dev libbz2-dev |  | ||||||
|         sudo apt-get -y install libssl-dev libicu-dev unzip |  | ||||||
|         sudo apt-get clean |  | ||||||
|         rm -rf /tmp/unar &> /dev/null |  | ||||||
|         mkdir /tmp/unar |  | ||||||
|         cd /tmp/unar |  | ||||||
|         wget -qO unar1.7_src.zip http://theunarchiver.googlecode.com/files/unar1.7_src.zip |  | ||||||
|         unzip -o unar1.7_src.zip |  | ||||||
|         cd The\ Unarchiver/XADMaster |  | ||||||
|         make -f Makefile.linux |  | ||||||
|         sudo mv lsar unar /usr/local/bin |  | ||||||
|         cd ../Extra |  | ||||||
|         sudo mv lsar.1 unar.1 /usr/local/man/man1 |  | ||||||
|         cd |  | ||||||
|         rm -rf /tmp/unar |  | ||||||
|     fi |  | ||||||
|     sudo mandb &> /dev/null |  | ||||||
| else |  | ||||||
|     echo "A2SERVER: The Unarchiver has already been installed." |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| sudo wget -q -O /usr/local/bin/afpsync appleii.ivanx.com/a2server/scripts/tools/afpsync.txt |  | ||||||
| sudo chmod ugo+x /usr/local/bin/afpsync |  | ||||||
| sudo wget -q -O /usr/local/bin/afptype appleii.ivanx.com/a2server/scripts/tools/afptype.txt |  | ||||||
| sudo chmod ugo+x /usr/local/bin/afptype |  | ||||||
| sudo wget -q -O /usr/local/bin/mkatinit appleii.ivanx.com/a2server/scripts/tools/mkatinit.txt |  | ||||||
| sudo chmod ugo+x /usr/local/bin/mkatinit |  | ||||||
| sudo wget -q -O /usr/local/bin/mkvolinfo appleii.ivanx.com/a2server/scripts/tools/mkvolinfo.txt |  | ||||||
| sudo chmod ugo+x /usr/local/bin/mkvolinfo |  | ||||||
| sudo wget -q -O /usr/local/bin/cppo appleii.ivanx.com/a2server/scripts/tools/cppo.txt |  | ||||||
| sudo chmod ugo+x /usr/local/bin/cppo |  | ||||||
| sudo wget -q -O /usr/local/etc/a2server-help.txt appleii.ivanx.com/a2server/scripts/tools/a2server-help.txt |  | ||||||
| sudo wget -q -O /usr/local/etc/a2server-aliases appleii.ivanx.com/a2server/scripts/tools/a2server-aliases.txt |  | ||||||
|  |  | ||||||
| grep a2server-aliases /etc/bash.bashrc > /dev/null || \ |  | ||||||
| echo "source /usr/local/etc/a2server-aliases" | sudo tee -a /etc/bash.bashrc > /dev/null |  | ||||||
|  |  | ||||||
| [[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]] && motd="/etc/issue" || motd="/etc/motd" |  | ||||||
| if [[ ! $(grep A2SERVER $motd) ]]; then |  | ||||||
|  	echo | sudo tee -a $motd > /dev/null |  | ||||||
| 	echo "Type 'system-shutdown' to turn off A2SERVER." | sudo tee -a $motd > /dev/null |  | ||||||
| 	echo "Type 'a2server-setup' to configure network boot." | sudo tee -a $motd > /dev/null |  | ||||||
| 	echo "Type 'a2server-help' for a list of other commands." | sudo tee -a $motd > /dev/null |  | ||||||
| 	echo | sudo tee -a $motd > /dev/null |  | ||||||
| fi |  | ||||||
| @@ -1,415 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| # A2SERVER -- a virtual machine for sharing files to Apple II clients |  | ||||||
| # by Ivan X, ivan@ivanx.com |  | ||||||
|  |  | ||||||
| # Installs Netatalk 2.2.4 for debian/raspbian (Wheezy) or Ubuntu (12.04) |  | ||||||
| # last update: 3-Mar-15 |  | ||||||
|  |  | ||||||
| # The lastest version of this document, and the ready-to-use premade |  | ||||||
| # virtual machine, will be at http://appleii.ivanx.com . |  | ||||||
|  |  | ||||||
| # Please send corrections and comments to ivan@ivanx.com |  | ||||||
|  |  | ||||||
| # Thanks to Steven Hirsch, Geoff Body, Peter Wong, Tony Diaz, and others |  | ||||||
| # at comp.sys.apple2 for the work they've done and insight they've |  | ||||||
| # offered which made it possible to put this together. |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # --- Installing netatalk |  | ||||||
|  |  | ||||||
| isRpi= |  | ||||||
| [[ -f /usr/bin/raspi-config ]] && isRpi=1 |  | ||||||
|  |  | ||||||
| isDebian= |  | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1-2 < /etc/debian_version) == "7." ) && ( $(uname -m) == "i686" ) ]] && isDebian=1 |  | ||||||
|  |  | ||||||
| # skip this if already done |  | ||||||
| if [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(cat /usr/local/etc/A2SERVER-version) >= 101 )); then |  | ||||||
|  |  | ||||||
|     echo "A2SERVER: Netatalk is already installed." |  | ||||||
|      |  | ||||||
| else |  | ||||||
|  |  | ||||||
|     echo "A2SERVER: Installing Netatalk (this will take a while)..." |  | ||||||
|      |  | ||||||
|     # stop Netatalk if running (during upgrade) |  | ||||||
|     [[ $(ps --no-headers -C afpd) ]] && sudo /etc/init.d/netatalk stop |  | ||||||
|      |  | ||||||
|     if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then |  | ||||||
|         # prepare for installing packages |  | ||||||
|         sudo apt-get -y update |  | ||||||
|         touch /tmp/a2server-packageReposUpdated |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     compileFromSource=1 |  | ||||||
|     while [[ $isRpi || $isDebian ]]; do |  | ||||||
|         # Install runtime libraries needed by Netatalk |  | ||||||
|         if [[ $(apt-cache search '^libdb4.8$') ]]; then |  | ||||||
|             sudo apt-get -y install libdb4.8 |  | ||||||
|         elif [[ $(apt-cache search '^libdb5.1$') ]]; then |  | ||||||
|             sudo apt-get -y install libdb5.1 |  | ||||||
|         else |  | ||||||
|             break |  | ||||||
|         fi |  | ||||||
|         if [[ $(apt-cache search '^libssl1.0.0$') ]]; then |  | ||||||
|             sudo apt-get -y install libssl1.0.0 |  | ||||||
|         elif [[ $(apt-cache search '^libssl0.9.8$') ]]; then |  | ||||||
|             sudo apt-get -y install libssl0.9.8 |  | ||||||
|         else |  | ||||||
|             break |  | ||||||
|         fi |  | ||||||
|         if [[ $(apt-cache search '^libgcrypt11$') ]]; then |  | ||||||
|             sudo apt-get -y install libgcrypt11 |  | ||||||
|         else |  | ||||||
|             break |  | ||||||
|         fi |  | ||||||
|          |  | ||||||
|         # install Netatalk |  | ||||||
|         if [[ $isRpi ]]; then |  | ||||||
|             { wget -qO- /tmp/netatalk.tgz ivanx.com/a2server/files/netatalk224-rpi.tgz | sudo tar Pzx; } 2> /dev/null |  | ||||||
|         elif [[ $isDebian ]]; then |  | ||||||
|             { wget -qO- /tmp/netatalk.tgz ivanx.com/a2server/files/netatalk224-debian7_x86.tgz | sudo tar Pzx; } 2> /dev/null |  | ||||||
|         fi |  | ||||||
|         sudo mandb &> /dev/null |  | ||||||
|          |  | ||||||
|         [[ -f /usr/local/sbin/atalkd ]] && compileFromSource= |  | ||||||
|  |  | ||||||
|         break |  | ||||||
|     done |  | ||||||
|  |  | ||||||
|     if [[ $compileFromSource ]]; then |  | ||||||
|         # Install development libraries needed by Netatalk |  | ||||||
|         sudo apt-get -y install build-essential |  | ||||||
|         if [[ $(apt-cache search '^libdb4.8-dev$') ]]; then |  | ||||||
|             sudo apt-get -y install libdb4.8-dev |  | ||||||
|         elif [[ $(apt-cache search '^libdb5.1-dev$') ]]; then |  | ||||||
|             sudo apt-get -y install libdb5.1-dev |  | ||||||
|         else |  | ||||||
|             echo "A2SERVER: WARNING: unknown version of libdb-dev is being installed" |  | ||||||
|             sudo apt-get -y install libdb-dev |  | ||||||
|         fi |  | ||||||
|         sudo apt-get -y install libssl-dev |  | ||||||
|         sudo apt-get -y install libgcrypt11-dev |  | ||||||
|         sudo apt-get clean |  | ||||||
|          |  | ||||||
|         # get Netatalk |  | ||||||
|         rm -rf /tmp/netatalk &> /dev/null |  | ||||||
|         mkdir /tmp/netatalk |  | ||||||
|         cd /tmp/netatalk |  | ||||||
|          |  | ||||||
|         wget -q "http://downloads.sourceforge.net/project/netatalk/netatalk/2.2.4/netatalk-2.2.4.tar.gz" |  | ||||||
|         tar zxf netatalk-2.2.4.tar.gz |  | ||||||
|         cd netatalk-2.2.4 |  | ||||||
|          |  | ||||||
|         # Patch the source so file dates are preserved during a GS/OS folder copy, |  | ||||||
|         #   and the AsanteTalk bridge consistently starts up in AppleTalk Phase 2 |  | ||||||
|         #   and the Dayna bridge doesn't crash GS/OS |  | ||||||
|         # props to Steven Hirsch for these |  | ||||||
|         sed -i ':a;N;$!ba;s/case FILPBIT_ATTR :\n *change_mdate = 1;\n/case FILPBIT_ATTR :\n/g' etc/afpd/file.c |  | ||||||
|         sed -i 's/rtmp->rt_iface == iface/rtmp->rt_iface != iface/g' etc/atalkd/main.c |  | ||||||
|      |  | ||||||
|         # prepare to build Netatalk |  | ||||||
|         ./configure --enable-debian --enable-ddp --enable-a2boot |  | ||||||
|      |  | ||||||
|         # uninstall Netatalk if already installed |  | ||||||
|         [[ -f /usr/local/sbin/afpd ]] && sudo make uninstall |  | ||||||
|          |  | ||||||
|         # compile and install Netatalk |  | ||||||
|         make |  | ||||||
|         sudo make install |  | ||||||
|          |  | ||||||
|         # to remove the Netatalk source code (optional), type: |  | ||||||
|         cd |  | ||||||
|         rm -rf /tmp/netatalk |  | ||||||
|     fi     |  | ||||||
| fi |  | ||||||
|      |  | ||||||
| # --- Configuring Netatalk |  | ||||||
|  |  | ||||||
| echo "A2SERVER: Configuring Netatalk..." |  | ||||||
|  |  | ||||||
| # if missing Netatalk startup file, download a fresh one |  | ||||||
| if [ ! -f /etc/init.d/netatalk ]; then |  | ||||||
|     echo "A2SERVER: Downloading new Netatalk startup script..." |  | ||||||
|     sudo wget -qO /etc/init.d/netatalk ivanx.com/a2server/files/netatalk-init.d-clean.txt |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # make the Netatalk startup script work correctly |  | ||||||
| sudo sed -i 's/bin\/sh/bin\/bash/' /etc/init.d/netatalk |  | ||||||
|  |  | ||||||
| # enable AppleTalk networking support in Netatalk, and run in background |  | ||||||
| sudo sed -i 's/#ATALKD_RUN=no/ATALKD_RUN=yes/' /etc/default/netatalk |  | ||||||
| sudo sed -i 's/#ATALK_BGROUND=no/ATALK_BGROUND=yes/' /etc/default/netatalk |  | ||||||
| if [[ ! $(grep 'kernelRelease' /etc/init.d/netatalk) ]]; then |  | ||||||
|     sudo sed -i 's@\(\tif \[ x\"$ATALKD_RUN\)@\n\t# check for valid AppleTalk kernel module\n\t[[ $ATALKD_RUN == "yes" ]] \&\& { kernelRelease=$(uname -r); kernelMajorRelease=$(cut -d "." -f 1  <<< $kernelRelease); kernelMinorRelease=$(cut -d "." -f 2  <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); kernelPatchRelease=$(cut -d "." -f 3- <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); [[ ( $kernelMajorRelease -eq 3 \&\& $kernelMinorRelease -ge 12 \&\& $kernelMinorRelease -le 15 ) \&\& ( ! ( -f /usr/bin/raspi-config \&\& $kernelMinorRelease -eq 12 \&\& $kernelPatchRelease -ge 25 ) ) \&\& ( ( ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ) || $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d " ") != "ecb239fc084c36de93f6926e7749b80f6024f269" ) ]] \&\& { ATALKD_RUN=no; echo "[AppleTalk networking is not available.]" 1>\&2; } }\n\n\1@' /etc/init.d/netatalk |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # enable network boot support in netatalk |  | ||||||
| sudo sed -i 's/timelord/a2boot/g' /etc/init.d/netatalk |  | ||||||
| sudo sed -i 's/TIMELORD/A2BOOT/g' /etc/init.d/netatalk |  | ||||||
| sudo sed -i 's/#A2BOOT_RUN=no/A2BOOT_RUN=yes/' /etc/default/netatalk |  | ||||||
|  |  | ||||||
| # allow Guest users to be able to network boot |  | ||||||
| sudo sed -i "s/#AFPD_GUEST=nobody/AFPD_GUEST=$USER/" /etc/default/netatalk |  | ||||||
| # (For a Guest user with different permissions than the compile-time user, create a |  | ||||||
| # Linux user, and then specify that user for AFPD_GUEST instead.) |  | ||||||
|  |  | ||||||
| # create a symbolic link to the startup configuration file in netatalk configuration folder |  | ||||||
| [[ -L /usr/local/etc/netatalk/netatalk.conf ]] \ |  | ||||||
| || sudo ln -s /etc/default/netatalk /usr/local/etc/netatalk/netatalk.conf |  | ||||||
|  |  | ||||||
| # create a symbolic link to the netatalk configuration folder in /etc |  | ||||||
| [[ -L /etc/netatalk ]] || sudo ln -s /usr/local/etc/netatalk /etc/netatalk |  | ||||||
|  |  | ||||||
| if [[ ! $(grep '^- -ddp.*uams_randnum.so' /usr/local/etc/netatalk/afpd.conf) ]]; then |  | ||||||
|     # set up to allow Guest, Cleartext, RandNum, DHX, and DHX2 login |  | ||||||
|     # disable DHX (DHCAST128) on Raspberry Pi, which refuses uams if the config string is too long |  | ||||||
|     [[ -f /usr/bin/raspi-config ]] && dhx="" || dhx="uams_dhx.so," |  | ||||||
|     echo -n -e \ |  | ||||||
|     "- -ddp -tcp -uamlist uams_guest.so,uams_clrtxt.so,uams_randnum.so" \ |  | ||||||
|     | sudo tee -a /usr/local/etc/netatalk/afpd.conf > /dev/null |  | ||||||
|     echo -e ",${dhx}uams_dhx2.so" \ |  | ||||||
|     | sudo tee -a /usr/local/etc/netatalk/afpd.conf > /dev/null |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # replace home folder share and end of file mark with share placeholders |  | ||||||
| sudo sed -i 's/^~/#share1\n\n#share2/' \ |  | ||||||
| /usr/local/etc/netatalk/AppleVolumes.default |  | ||||||
|  |  | ||||||
| # disable default volume options for Mac OS X clients |  | ||||||
| sudo sed -i 's/^:DEFAULT/#:DEFAULT/' \ |  | ||||||
| /usr/local/etc/netatalk/AppleVolumes.default |  | ||||||
|  |  | ||||||
| if [[ ! $(grep ^eth0 /usr/local/etc/netatalk/atalkd.conf) && ! $(grep ^wlan0 /usr/local/etc/netatalk/atalkd.conf) ]]; then |  | ||||||
|     # enable netatalk on the default network interface |  | ||||||
|     # needs -router and -zone to prevent GS/OS AppleShare CDEV crash when used |  | ||||||
|     # with Dayna or Asante bridges |  | ||||||
|     echo -e 'eth0 -router -phase 2 -net 1 -zone "A2SERVER"' \ |  | ||||||
|     | sudo tee -a /usr/local/etc/netatalk/atalkd.conf > /dev/null |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # Raspberry Pi |  | ||||||
| if [[ $isRpi ]]; then |  | ||||||
|     # blink LED upon netatalk startup so you know when to attach power to an AsanteTalk bridge |  | ||||||
|     if [[ ! $(grep 'led0' /etc/init.d/netatalk) ]]; then |  | ||||||
|         sudo sed -i ':a;N;$!ba;s/fi\n}/fi\n\n    # blink LED on Raspberry Pi\n    ([[ -e \/sys\/class\/leds\/ACT ]] \&\& led=ACT || led=led0; echo none > \/sys\/class\/leds\/$led\/trigger; for i in {1..20}; do echo 1 > \/sys\/class\/leds\/$led\/brightness; sleep 0.25; echo 0 > \/sys\/class\/leds\/$led\/brightness; sleep 0.25; done; echo mmc0 > \/sys\/class\/leds\/$led\/trigger) \&\n}/' /etc/init.d/netatalk |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     # set console port login to 4800 bps for usage with Apple II (using RPi console cable) |  | ||||||
|     sudo sed -i 's/ttyAMA0 115200/ttyAMA0 4800/' /etc/inittab |  | ||||||
|  |  | ||||||
|     # enable serial console login with USB-serial adapter |  | ||||||
|     # 10-4-13: creates unwanted console messages if no adapter present, |  | ||||||
|     #   and physical port isn't predictable with more than one adapter present, so |  | ||||||
|     #   has been superseded by scanttyUSB supplied by A2CLOUD install |  | ||||||
|     #if [[ ! $(grep 'ttyUSB0 19200' /etc/inittab) ]]; then |  | ||||||
|     #    echo -e "\n\n#for USB-to-serial adapter with Prolific PL2303 chipset\nT1:23:respawn:/sbin/getty -L ttyUSB0 19200 vt100" | sudo tee -a /etc/inittab > /dev/null |  | ||||||
|     #fi |  | ||||||
| fi |  | ||||||
|     |  | ||||||
| # set up GSFILES share (for GS data files, not GSOS system) |  | ||||||
| # classic Mac OS file names are allowed (31 chars, mixed case, everything but colons) |  | ||||||
| sudo sed -i \ |  | ||||||
| 's/^#share1/\/media\/A2SHARED\/GSFILES\ GSFILES ea:ad/' \ |  | ||||||
| /usr/local/etc/netatalk/AppleVolumes.default |  | ||||||
| [[ -d /media/A2SHARED/GSFILES ]] || mkdir -p /media/A2SHARED/GSFILES |  | ||||||
|  |  | ||||||
| # set up A2FILES share (for ProDOS 8 files, and GS/OS system) |  | ||||||
| # file names must be ProDOS 8 compliant (all caps, 15 chars, letters/numbers/periods only) |  | ||||||
| # lowercase filenames will be converted to upper automatically |  | ||||||
| # need for GS/OS system because it may refer to files by either upper or lower |  | ||||||
| sudo sed -i \ |  | ||||||
| 's/^#share2/\/media\/A2SHARED\/A2FILES\ A2FILES options:prodos\ casefold:toupper ea:ad/' \ |  | ||||||
| /usr/local/etc/netatalk/AppleVolumes.default |  | ||||||
| [[ -d /media/A2SHARED/A2FILES ]] || mkdir -p /media/A2SHARED/A2FILES |  | ||||||
| if [[ ! -d /media/A2SHARED/A2FILES/.AppleDesktop ]]; then |  | ||||||
|     cd /media/A2SHARED/A2FILES |  | ||||||
|     mkdir .AppleDesktop |  | ||||||
|     ln -s .AppleDesktop .APPLEDESKTOP |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # set up ADTDISKS share (ADTPro disk image folder, if A2CLOUD is installed)     |  | ||||||
| # classic Mac OS file names are allowed (31 chars, mixed case, everything but colons) |  | ||||||
| if [[ -d /usr/local/adtpro/disks ]]; then # A2CLOUD/ADTPro installed |  | ||||||
|     if [[ ! -d /media/A2SHARED/ADTDISKS ]]; then |  | ||||||
|         ln -s /usr/local/adtpro/disks /media/A2SHARED/ADTDISKS |  | ||||||
|     fi |  | ||||||
|     if [[ ! $(grep ADTDISKS /usr/local/etc/netatalk/AppleVolumes.default) ]]; then |  | ||||||
|         sudo sed -i 's@^# End of File@/media/A2SHARED/ADTDISKS ADTDISKS ea:ad\n\n# End of File@' /usr/local/etc/netatalk/AppleVolumes.default |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # to make Netatalk start up when the server boots: |  | ||||||
| sudo update-rc.d netatalk defaults &> /dev/null |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # --- Setting up users |  | ||||||
|  |  | ||||||
| # At this point, the server is usable for Guest access. |  | ||||||
|  |  | ||||||
| # skip if we've already done this |  | ||||||
| if [[ -f /usr/local/etc/netatalk/afppasswd ]]; then |  | ||||||
|  |  | ||||||
|     echo "A2SERVER: Netatalk user logins have already been set up." |  | ||||||
|  |  | ||||||
| else |  | ||||||
|  |  | ||||||
|     echo |  | ||||||
|     echo "A2SERVER: Setting up AFP password 'apple2' for Apple II and Mac clients." |  | ||||||
|     # echo "A2SERVER: Enter 'apple2' or another password of up to eight characters." |  | ||||||
|     echo     |  | ||||||
|     # set registered user login using RandNum authentication |  | ||||||
|     sudo afppasswd -c |  | ||||||
|     sudo sed -i 's/^pi.*$/pi:6170706C65320000:****************:********/' /usr/local/etc/netatalk/afppasswd |  | ||||||
|     # while [[ ! $(sudo afppasswd -a $USER) ]]; do |  | ||||||
|     #     true |  | ||||||
|     # done |  | ||||||
|     # (The afppasswd -c only needs to ever be done once. You can repeat |  | ||||||
|     #   the afppasswd -a to make Netatalk logins for other Linux users.) |  | ||||||
|  |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # Check AppleTalk kernel module for existence and validity |  | ||||||
|  |  | ||||||
| # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) |  | ||||||
| kernelRelease=$(uname -r) |  | ||||||
| kernelMajorRelease=$(cut -d '.' -f 1  <<< $kernelRelease) |  | ||||||
| kernelMinorRelease=$(cut -d '.' -f 2  <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') |  | ||||||
| kernelPatchRelease=$(cut -d '.' -f 3- <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') |  | ||||||
|  |  | ||||||
| # if on kernel 3.12 through 3.15, check if we need to delete AppleTalk module to prevent kernel panics |  | ||||||
| if [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -ge 12 && $kernelMinorRelease -le 15 ]]; then |  | ||||||
|     # if not RPi, or RPi without ivanx-fixed AppleTalk module, delete the module |  | ||||||
|     if [[ ! ( $isRpi && $kernelMinorRelease -eq 12 && $kernelPatchRelease -ge 25 ) ]]; then |  | ||||||
|         if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then |  | ||||||
|             if [[ $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then |  | ||||||
|                 # stop Netatalk |  | ||||||
|                 sudo /etc/init.d/netatalk stop &> /dev/null |  | ||||||
|                 echo "A2SERVER: Deleting defective AppleTalk kernel module." |  | ||||||
|                 sudo rmmod appletalk 2> /dev/null |  | ||||||
|                 sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk |  | ||||||
|                 # disable single-user mode on Pi (other Linux can use Recovery boot) |  | ||||||
|                 if [[ $isRpi && $(grep ' single' /boot/cmdline.txt 2> /dev/null) ]]; then |  | ||||||
|                     echo "A2SERVER: Disabling single-user mode for next boot." |  | ||||||
|                     sudo sed -i 's/ single//' /boot/cmdline.txt |  | ||||||
|                     touch /tmp/singleUser # so note to restart can display following install |  | ||||||
|                 fi |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # --- Start Netatalk (if not running) |  | ||||||
|  |  | ||||||
| bground= |  | ||||||
| if [[ $(grep 'ATALK_BGROUND=yes' /etc/default/netatalk) ]]; then |  | ||||||
|     bground=1 |  | ||||||
|     sudo sed -i 's/ATALK_BGROUND=yes/ATALK_BGROUND=no/' /etc/default/netatalk |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| [[ $(ps --no-headers -C afpd) ]] || sudo /etc/init.d/netatalk start 2> /dev/null |  | ||||||
|  |  | ||||||
| echo |  | ||||||
| echo "A2SERVER: Netatalk is installed, configured, and running." |  | ||||||
| echo |  | ||||||
|  |  | ||||||
| # if atalkd isn't running (no AppleTalk), and this is a Rasbperry Pi: |  | ||||||
| if [[ ( ! $(ps aux | grep [a]talkd) ) && ( $isRpi ) ]]; then     |  | ||||||
|      |  | ||||||
|     # if AppleTalk module exists, try to load it |  | ||||||
|     if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # module present, but not loaded? |  | ||||||
|         sudo depmod |  | ||||||
|         sudo modprobe appletalk |  | ||||||
|         if [[ $(lsmod | grep appletalk) ]]; then |  | ||||||
|             # if it loaded, restart netatalk |  | ||||||
|             sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart |  | ||||||
|         else |  | ||||||
|             # if we didn't load it successfully, delete it |  | ||||||
|             sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk |  | ||||||
|         fi |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     # if no AppleTalk module, try to download it from a2server site |  | ||||||
|     if [[ ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # check for rpi kernel module |  | ||||||
|         echo "A2SERVER: Attempting to install AppleTalk kernel module for Raspbian..." |  | ||||||
|         wget -qO /tmp/appletalk.ko.gz appleii.ivanx.com/a2server/files/appletalk-$kernelRelease.ko.gz |  | ||||||
|         if [[ $? -eq 0 ]]; then |  | ||||||
|             # if we found a prebuilt one on a2server site, install it and load it |  | ||||||
|             gunzip -f /tmp/appletalk.ko.gz |  | ||||||
|             sudo mkdir -p /lib/modules/$kernelRelease/kernel/net/appletalk |  | ||||||
|             sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk |  | ||||||
|             sudo depmod |  | ||||||
|             sudo modprobe appletalk |  | ||||||
|             if [[ $(lsmod | grep appletalk) ]]; then |  | ||||||
|                 # if it loaded, restart netatalk |  | ||||||
|                 sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart |  | ||||||
|             else |  | ||||||
|                 # if we didn't load it successfully, remove it |  | ||||||
|                 sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|  |  | ||||||
|         # if we still don't have AppleTalk, try to use rpi-update |  | ||||||
|         rm /tmp/rpiUpdate 2> /dev/null |  | ||||||
|         if [[ ! $(ps aux | grep [a]talkd) ]]; then |  | ||||||
|             # use specific rpi-update commit (at https://github.com/Hexxeh/rpi-firmware/) |  | ||||||
|             # from when AppleTalk was added/fixed, so we have a consistent firmware that |  | ||||||
|             # we're loading until the next proper release of Raspbian that includes it |  | ||||||
|             # |  | ||||||
|             # 10-26-13: when AppleTalk was added to Raspbian: |  | ||||||
|             #   sudo rpi-update 9530adbe31fe6b8e05b3bd5cfadfc90f067f5362 |  | ||||||
|             # sudo modprobe appletalk 2> /dev/null |  | ||||||
|             # if [[ $(lsmod | grep appletalk) ]]; then |  | ||||||
|                 # if it loaded, restart netatalk |  | ||||||
|             #     sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart |  | ||||||
|             # fi |  | ||||||
|             # |  | ||||||
|             # 07-23-14: when AppleTalk was fixed after kernel panics in Raspbian 2014-06-20 (kernel 3.12.22+) |  | ||||||
|             sudo rm /boot/.firmware_revision |  | ||||||
|             sudo rpi-update cfd9a203590737f9536de70a1e01db25a3e8e069 |  | ||||||
|             touch /tmp/rpiUpdate # so note to restart can display following install |  | ||||||
|         fi |  | ||||||
|  |  | ||||||
|         if [[ ! $(ps aux | grep [a]talkd) ]]; then |  | ||||||
|             if [[ -f /tmp/rpiUpdate ]]; then |  | ||||||
|                 echo |  | ||||||
|                 echo "AppleTalk networking is installed but not yet active." |  | ||||||
|                 echo "When installation is complete, please restart your Raspberry Pi" |  | ||||||
|                 echo "when asked or by typing 'system-restart' at the Linux prompt" |  | ||||||
|                 echo "to allow Apple II computers to connect." |  | ||||||
|                 echo |  | ||||||
|             else |  | ||||||
|                 echo |  | ||||||
|                 echo "AppleTalk networking could not be activated" |  | ||||||
|                 echo "for your Raspbian kernel version ($kernelRelease)." |  | ||||||
|                 echo "Please try restarting with 'system-restart'. If that doesn't work," |  | ||||||
|                 echo "you're not going to be able to connect from an Apple II." |  | ||||||
|                 echo "See http://appleii.ivanx.com/a2server for help." |  | ||||||
|                 echo |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| if [[ $bground ]]; then |  | ||||||
|     sudo sed -i 's/ATALK_BGROUND=no/ATALK_BGROUND=yes/' /etc/default/netatalk |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # --- Set up Avahi-Daemon (Bonjour/mDNS) |  | ||||||
| # thanks to: http://missingreadme.wordpress.com/2010/05/08/how-to-set-up-afp-filesharing-on-ubuntu |  | ||||||
|  |  | ||||||
| if [[ ! $(dpkg -l avahi-daemon 2> /dev/null | grep ^ii) || ! $(dpkg -l libnss-mdns 2> /dev/null | grep ^ii) ]]; then |  | ||||||
|     echo "A2SERVER: Installing Avahi-Daemon (Bonjour/mDNS)..." |  | ||||||
|     if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then |  | ||||||
|         # prepare for installing packages |  | ||||||
|         sudo apt-get -y update |  | ||||||
|         touch /tmp/a2server-packageReposUpdated |  | ||||||
|     fi |  | ||||||
|     sudo apt-get -y install avahi-daemon libnss-mdns &> /dev/null |  | ||||||
| fi |  | ||||||
| sudo sed -i 's/^\(hosts.*\)$/\1 mdns/' /etc/nsswitch.conf |  | ||||||
| if [[ ! -f /etc/avahi/services/afpd.service && ! -f /etc/avahi/services/afpd.service_disabled ]]; then |  | ||||||
|     echo -e '<?xml version="1.0" standalone="no"?><!--*-nxml-*-->\n<!DOCTYPE service-group SYSTEM "avahi-service.dtd">\n<service-group>\n    <name replace-wildcards="yes">%h</name>\n    <service>\n        <type>_afpovertcp._tcp</type>\n        <port>548</port>\n    </service>\n    <service>\n        <type>_device-info._tcp</type>\n        <port>0</port>\n        <txt-record>model=MacPro</txt-record>\n    </service>\n</service-group>' | sudo tee /etc/avahi/services/afpd.service > /dev/null |  | ||||||
| fi |  | ||||||
| sudo /etc/init.d/avahi-daemon restart &> /dev/null |  | ||||||
| @@ -1,444 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # this script downloads and installs the Apple boot blocks required |  | ||||||
| # for booting an Apple II client over the network, and places |  | ||||||
| # BASIC.SYSTEM on the shared drive and configures it to be the startup |  | ||||||
| # program (for Apple IIe users, and IIgs users in ProDOS network mode). |  | ||||||
| # It also can download and install GS/OS for a network boot configuration. |  | ||||||
|  |  | ||||||
| gsosDir="/media/A2SHARED/A2FILES" |  | ||||||
| imagesDir=$gsosDir/GSOS.INSTALLER/IMAGES |  | ||||||
| imageToolsDir=$gsosDir/GSOS.INSTALLER/IMAGE.TOOLS |  | ||||||
| netInstallDir=$gsosDir/GSOS.INSTALLER/NET.INSTALL |  | ||||||
|  |  | ||||||
| p8Dir="/media/A2SHARED/A2FILES" |  | ||||||
| diskToolsP8Dir=$p8Dir/DISK.TOOLS.P8 |  | ||||||
|  |  | ||||||
| commDir="/media/A2SHARED/A2FILES/COMM" |  | ||||||
| spectrumDir=$commDir/SPECTRUM |  | ||||||
| protermDir=$commDir/PROTERM |  | ||||||
| zlinkDir=$commDir/Z.LINK |  | ||||||
| adtproDir=$commDir/ADTPRO |  | ||||||
|  |  | ||||||
| # bail out on automated netboot setup unless -b is also specified |  | ||||||
| [[ -f /tmp/a2server-autoAnswerYes ]] && autoAnswerYes=1 || autoAnswerYes= |  | ||||||
| if [[ ! $autoAnswerYes || -f /tmp/a2server-setupNetBoot ]]; then |  | ||||||
|      |  | ||||||
|     if [[ ! $autoAnswerYes ]]; then |  | ||||||
|         echo |  | ||||||
|         echo "Do you want to set up A2SERVER to be able to boot Apple II" |  | ||||||
|         echo -n "computers over the network? " |  | ||||||
|         read |  | ||||||
|     fi |  | ||||||
|      |  | ||||||
|     if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|      |  | ||||||
|         nbmode=1 |  | ||||||
|         echo |  | ||||||
|          |  | ||||||
|         sudo true |  | ||||||
|         mkdir -p /tmp/netboot |  | ||||||
|         cd /tmp/netboot |  | ||||||
|          |  | ||||||
|         # this will get "Disk 7" (Apple II Setup) as a raw (block dump) image |  | ||||||
|         if [[ ! -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Boot\ Blocks ]] \ |  | ||||||
|         || [[ ! -f /usr/local/etc/netatalk/a2boot/ProDOS16\ Image ]] \ |  | ||||||
|         || [[ ! -f /usr/local/etc/netatalk/a2boot/Apple\ :2f:2fe\ Boot\ Blocks ]]; then |  | ||||||
|             echo "A2SERVER: Downloading Apple II Boot Blocks..." |  | ||||||
|             cd /tmp/netboot |  | ||||||
|              |  | ||||||
|             wget -qO 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 |  | ||||||
|             unar -k skip Disk_7_of_7-Apple_II_Setup.sea.bin &> /dev/null |  | ||||||
|             truncate -s 819284 'Disk 7 of 7-Apple II Setup.sea' |  | ||||||
|             dd if='Disk 7 of 7-Apple II Setup.sea' of=APPLE2SETUP.HDV bs=84 skip=1 2> /dev/null |  | ||||||
|                  |  | ||||||
|             # copy the Boot Blocks into the right place |  | ||||||
|             mkdir -p a2setup |  | ||||||
|             sudo mount -t hfs -o ro,loop APPLE2SETUP.HDV a2setup |  | ||||||
|             sudo mkdir -p /usr/local/etc/netatalk/a2boot |  | ||||||
|             sudo cp -p a2setup/System\ Folder/* /usr/local/etc/netatalk/a2boot |  | ||||||
|             sudo umount a2setup |  | ||||||
|             sudo mv /usr/local/etc/netatalk/a2boot/Apple* /usr/local/etc/netatalk/a2boot/'Apple :2f:2fe Boot Blocks' |  | ||||||
|              |  | ||||||
|             cd /usr/local/etc/netatalk/a2boot         |  | ||||||
|             # thanks to Geoff Body for these Boot Blocks patches |  | ||||||
|             # fix cleartext password login bug |  | ||||||
|             echo -n -e "\xA8\xA2\x01\xBD\x80\x38\x99\xA0\x38\xC8\xE8\xE0\x09\x90\xF4" | \ |  | ||||||
|               sudo dd of='Apple :2f:2fe Boot Blocks' bs=19779 seek=1 conv=notrunc 2> /dev/null |  | ||||||
|             echo -n -e "\xA8\xA2\x01\xBD\x80\x10\x99\xA0\x10\xC8\xE8\xE0\x09\x90\xF4" | \ |  | ||||||
|               sudo dd of='ProDOS16 Image' bs=22583 seek=1 conv=notrunc 2> /dev/null |  | ||||||
|             # enable typing "8" during GS/OS netboot to force ProDOS 8 boot |  | ||||||
|             echo -n -e "\x92" | sudo dd of='ProDOS16 Image' bs=256 seek=1 conv=notrunc 2> /dev/null |  | ||||||
|             echo -n -e "\x20\x7d\x14" | sudo dd of='ProDOS16 Image' bs=864 seek=1 conv=notrunc 2> /dev/null |  | ||||||
|             echo -n -e "\xad\x00\xc0\x29\xff\x00\xc9\xb8\x00\xd0\x06\xa9\x02\x00\x8d\x53\x14\xa9\x10\x0f\x60" | \ |  | ||||||
|               sudo dd of='ProDOS16 Image' bs=1661 seek=1 conv=notrunc 2> /dev/null |  | ||||||
|         fi |  | ||||||
|         echo "A2SERVER: Boot Blocks have been installed." |  | ||||||
|          |  | ||||||
|         # get a2server-tools if necessary |  | ||||||
|         if [[ ! -f /usr/local/bin/mkatinit ]] \ |  | ||||||
|         || [[ ! -f /usr/local/bin/afptype ]] \ |  | ||||||
|         || [[ ! -f /usr/local/bin/mkvolinfo ]] \ |  | ||||||
|         || [[ ! -f /usr/local/bin/afpsync ]]; then |  | ||||||
|             rm /tmp/2.tools &> /dev/null |  | ||||||
|             wget -q -O /tmp/2.tools appleii.ivanx.com/a2server/scripts/a2server-2-tools.txt |  | ||||||
|             chmod ugo+x /tmp/2.tools |  | ||||||
|             /tmp/2.tools |  | ||||||
|             rm /tmp/2.tools |  | ||||||
|         fi |  | ||||||
|      |  | ||||||
|         # put BASIC.SYSTEM at root for ProDOS 8 startup |  | ||||||
|         cp -p /usr/local/etc/netatalk/a2boot/Basic.System $gsosDir/BASIC.SYSTEM         |  | ||||||
|         afpsync -v $gsosDir > /dev/null |  | ||||||
|         afptype -p SYS -q $gsosDir/BASIC.SYSTEM |  | ||||||
|          |  | ||||||
|         # create tools for setting GS/OS or ProDOS 8 boot in battery RAM and rebooting. Props yet again to Geoff Body. |  | ||||||
|         if [[ ! -f $p8Dir/NETBOOT.P8 ]]; then |  | ||||||
|             echo |  | ||||||
|             echo "A2SERVER: Creating NETBOOT.P8..." |  | ||||||
|             touch $p8Dir/NETBOOT.P8 |  | ||||||
|             echo -n -e "\x38\x20\x1f\xfe\x90\x01\x60\xfb\x08\xc2\x30\xf4\x02\x00\xf4\x62\x00\xa2\x03\x0b\x22\x00\x00\xe1\x78\xf4\x00\x00\xf4\x00\x00\xab\xab\x2b\x38\xfb\xce\xf4\x03\xa9\x0c\x8d\x68\xc0\x9c\x47\xc0\x9c\x41\xc0\xa9\x09\x8d\x39\xc0\xa9\xc0\x8d\x39\xc0\x5c\x62\xfa\x00" | \ |  | ||||||
|               sudo dd of="$p8Dir/NETBOOT.P8" 2> /dev/null |  | ||||||
|             afpsync -v $p8Dir > /dev/null |  | ||||||
|             afptype -p SYS -q $p8Dir/NETBOOT.P8 |  | ||||||
|         fi |  | ||||||
|         if [[ ! -f $gsosDir/NETBOOT.GSOS ]]; then |  | ||||||
|             echo |  | ||||||
|             echo "A2SERVER: Creating NETBOOT.GSOS..." |  | ||||||
|             # create tool for setting GSOS boot in battery RAM and rebooting. Props yet again to Geoff Body. |  | ||||||
|             touch $gsosDir/NETBOOT.GSOS |  | ||||||
|             echo -n -e "\x38\x20\x1f\xfe\x90\x01\x60\xfb\x08\xc2\x30\xf4\x01\x00\xf4\x62\x00\xa2\x03\x0b\x22\x00\x00\xe1\x78\xf4\x00\x00\xf4\x00\x00\xab\xab\x2b\x38\xfb\xce\xf4\x03\xa9\x0c\x8d\x68\xc0\x9c\x47\xc0\x9c\x41\xc0\xa9\x09\x8d\x39\xc0\xa9\xc0\x8d\x39\xc0\x5c\x62\xfa\x00" | \ |  | ||||||
|               sudo dd of="$p8Dir/NETBOOT.GSOS" 2> /dev/null |  | ||||||
|             afpsync -v $gsosDir > /dev/null |  | ||||||
|             afptype -p SYS -q $gsosDir/NETBOOT.GSOS |  | ||||||
|         fi |  | ||||||
|      |  | ||||||
|         mkatinit -gs -d -f     # GS/OS registered user and Guest starts up with SYSTEM/FINDER |  | ||||||
|         mkatinit -d -f guest   # ProDOS 8 Guest starts up with BASIC.SYSTEM (no registered user) |  | ||||||
|      |  | ||||||
|         if [[ -f "/media/A2SHARED/A2FILES/SYSTEM/START.GS.OS" ]]; then |  | ||||||
|             echo "A2SERVER: GS/OS has already been downloaded and installed." |  | ||||||
|             gsosInstall=1 |  | ||||||
|         else |  | ||||||
|             if [[ ! $autoAnswerYes ]]; then |  | ||||||
|                 echo "You can set up GS/OS 6.0.1 on your network drive, for network boot." |  | ||||||
|                 echo -n "This may take a while. Download and install it now? " |  | ||||||
|                 read |  | ||||||
|             fi |  | ||||||
|             if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|                 gsosInstall=1 |  | ||||||
|      |  | ||||||
|                 # get GS/OS disks from Internet Archive and put them in IMAGES |  | ||||||
|                 # also dump contents into NET.INSTALL and modify scripts to work from there |  | ||||||
|                 # echo |  | ||||||
|                 # echo "Come back in a while. This takes a long time." |  | ||||||
|                 echo |  | ||||||
|                 echo "A2SERVER: Downloading GS/OS 6.0.1 installer disk images..." |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 mkdir -p $imagesDir |  | ||||||
|                 mkdir -p $netInstallDir |  | ||||||
|                 activeDisk=0 |  | ||||||
|                 for diskname in Install System.Disk SystemTools1 SystemTools2 Fonts synthLAB; do |  | ||||||
|                     outfile="$imagesDir/$(tr [:lower:] [:upper:] <<< $diskname)" |  | ||||||
|                     if [ ! -f $outfile ]; then |  | ||||||
|                         (( activeDisk++ )) |  | ||||||
|                         echo "A2SERVER: Disk ${activeDisk} of 6: $diskname" |  | ||||||
|                         wget -qO "Disk_${activeDisk}_of_7-$diskname.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_${activeDisk}_of_7-$diskname.sea.bin" |  | ||||||
|                         unar -k skip "Disk_${activeDisk}_of_7-$diskname.sea.bin" &> /dev/null |  | ||||||
|                         truncate -s 819284 "Disk ${activeDisk} of 7-${diskname}.sea" |  | ||||||
|                         dd if="Disk ${activeDisk} of 7-${diskname}.sea" of=${outfile} bs=84 skip=1 &> /dev/null |  | ||||||
|                         cppo -s -ad $outfile $netInstallDir 2> /dev/null |  | ||||||
|                     fi |  | ||||||
|                 done |  | ||||||
|                 rm *.sea* &> /dev/null |  | ||||||
|                 sed -i "s/\([^\\]\r:\)/\1A2FILES:GSOS.INSTALLER:NET.INSTALL:/g" $netInstallDir/INSTALL/SCRIPTS/* |  | ||||||
|      |  | ||||||
|                 afpsync -v $gsosDir > /dev/null |  | ||||||
|                  |  | ||||||
|                 # install GS/OS |  | ||||||
|                 # spec for GS/OS installer scripts: GS/OS Tech Note #64 |  | ||||||
|                 # http://www.1000bit.it/support/manuali/apple/technotes/iigs/tn.iigs.064.html |  | ||||||
|                 processScript () { |  | ||||||
|                     scriptEntries=$(cat $1 | tr '\r' '#' | tr '~' '\n' | sed 's/4#D/5/') |  | ||||||
|                     IFS=$'\n' |  | ||||||
|                     scriptEntries=($scriptEntries) |  | ||||||
|                     pathPrefix="/A2FILES/GSOS.INSTALLER/NET.INSTALL"$(tr ':' '/' <<< ${scriptEntries[0]##S*\\\\#}) |  | ||||||
|                     entryCount=${#scriptEntries[@]} |  | ||||||
|                     (( entryCount -= 2 )) |  | ||||||
|                     entryIndex=3 |  | ||||||
|                     while (( entryIndex < entryCount )); do |  | ||||||
|                         IFS='#' |  | ||||||
|                         scriptEntry=(${scriptEntries[entryIndex]}) |  | ||||||
|                         # echo $entryIndex $entryCount ${scriptEntry[1]} |  | ||||||
|                         action=${scriptEntry[1]:0:1} |  | ||||||
|                         sourcePathMixed=$(tr ':' '/' <<<  ${scriptEntry[5]}) |  | ||||||
|                         [[ ${sourcePathMixed:0:1} != '/' ]] && sourcePathMixed="${pathPrefix}/$sourcePathMixed" |  | ||||||
|                         sourcePath=$(tr [:lower:] [:upper:] <<< $sourcePathMixed) |  | ||||||
|                         targetPath=$gsosDir/$(tr ':' '/' <<< ${scriptEntry[6]} | tr [:lower:] [:upper:]) |  | ||||||
|                         # volumeName=$(cut -d/ -f 2 <<< $sourcePath) |  | ||||||
|                         targetParent=${targetPath%/*} |  | ||||||
|                         targetFile=${targetPath##*/} |  | ||||||
|                         sourceParent=${sourcePath%/*} |  | ||||||
|                         sourceFile=${sourcePath##*/} |  | ||||||
|                  |  | ||||||
|                         if [[ $action == 1 || $action == 2 ]]; then |  | ||||||
|                             mkdir -p $targetParent |  | ||||||
|                             echo "copying: $sourcePathMixed" |  | ||||||
|                             echo "     to: $targetPath" |  | ||||||
|                             echo |  | ||||||
|                             [[ ! -d $targetParent ]] && mkdir -p $targetParent |  | ||||||
|                             cp -p ${gsosDir%/*}$sourcePath $targetPath |  | ||||||
|                             [[ ! -d $targetParent/.AppleDouble ]] && mkdir -p $targetParent/.AppleDouble |  | ||||||
|                             cp -p ${gsosDir%/*}$sourceParent/.AppleDouble/$sourceFile $targetParent/.AppleDouble/$targetFile |  | ||||||
|                         elif [[ $action == 3 || $action == 4 ]]; then |  | ||||||
|                             if [[ -f "$targetPath" ]]; then |  | ||||||
|                                 echo "deleting $targetPath" |  | ||||||
|                                 rm "$targetPath" |  | ||||||
|                                 [[ -f $targetParent/.AppleDouble/$targetFile ]] && rm "$targetParent/.AppleDouble/$targetFile" |  | ||||||
|                             fi |  | ||||||
|                         fi |  | ||||||
|                         (( entryIndex++ )) |  | ||||||
|                     done |  | ||||||
|                     unset IFS |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 mkdir -p /tmp/netboot |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|      |  | ||||||
|                 echo "A2SERVER: Preparing GS/OS installer scripts..."     |  | ||||||
|                 # work through installer scripts |  | ||||||
|                 processScript $netInstallDir/INSTALL/SCRIPTS/INSTAL.SYS.FILE |  | ||||||
|                 processScript $netInstallDir/INSTALL/SCRIPTS/APPLESHARE |  | ||||||
|                 processScript $netInstallDir/INSTALL/SCRIPTS/SERVER.SYS.FILE |  | ||||||
|      |  | ||||||
|                 # sync netatalk database |  | ||||||
|                 afpsync -v $gsosDir > /dev/null |  | ||||||
|              |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|          |  | ||||||
|         if [[ ! $autoAnswerYes ]]; then |  | ||||||
|             echo |  | ||||||
|             echo "Do you want to download and install utilities for working with" |  | ||||||
|             echo -n "disk images and archive files in GS/OS? " |  | ||||||
|             read |  | ||||||
|         fi |  | ||||||
|         if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|      |  | ||||||
|             # download image tools and put them in IMAGE.TOOLS |  | ||||||
|             echo "A2SERVER: Downloading GS/OS disk image utilities..." |  | ||||||
|             mkdir -p $imageToolsDir |  | ||||||
|      |  | ||||||
|             # get Asimov2 (for GS/OS) |  | ||||||
|             echo -n "Asimov 2.0" |  | ||||||
|             if [[ -f $imageToolsDir/ASIMOV ]]; then |  | ||||||
|                 echo " is already installed." |  | ||||||
|             else |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 wget -q -nc http://www.ninjaforce.com/downloads/Asimov.shk |  | ||||||
|                 nulib2 -x -s Asimov.shk > /dev/null |  | ||||||
|                 cp -p Asimov/Asimov $imageToolsDir/ASIMOV |  | ||||||
|                 afpsync -v $gsosDir > /dev/null |  | ||||||
|                 cat Asimov/Asimov_rsrc_ >> $imageToolsDir/.AppleDouble/ASIMOV |  | ||||||
|                 afptype -p S16 -q $imageToolsDir/ASIMOV |  | ||||||
|             fi |  | ||||||
|          |  | ||||||
|             echo -n "GS-ShrinkIt 1.1" |  | ||||||
|             # get GS-ShrinkIt |  | ||||||
|             if [[ -f $imageToolsDir/GSHK ]]; then |  | ||||||
|                 echo " is already installed." |  | ||||||
|             else |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 wget -qO gshk.sea http://web.archive.org/web/20131031160750/http://nulib.com/library/gshk11.sea |  | ||||||
|                 #wget -qO gshk.sea http://www.nulib.com/library/gshk11.sea |  | ||||||
|                 nulib2 -x -s gshk.sea > /dev/null |  | ||||||
|                 cp -p GSHK $imageToolsDir/GSHK |  | ||||||
|                 afpsync -v $gsosDir > /dev/null |  | ||||||
|                 cat GSHK_rsrc_ >> $imageToolsDir/.AppleDouble/GSHK |  | ||||||
|                 afptype -p S16 -a DB07 -q $imageToolsDir/GSHK |  | ||||||
|             fi |  | ||||||
|      |  | ||||||
|             echo -n "MountIt 1.4"     |  | ||||||
|             # get MountIt (for GS/OS) |  | ||||||
|             if [[ -f $imageToolsDir/MOUNTIT.SHK ]]; then |  | ||||||
|                 echo " is already installed." |  | ||||||
|             else |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 wget -q -nc http://www.brutaldeluxe.fr/products/apple2gs/MOUNTIT.SHK |  | ||||||
|                 cp -p MOUNTIT.SHK $imageToolsDir/MOUNTIT.SHK |  | ||||||
|                 afpsync -v $gsosDir > /dev/null |  | ||||||
|                 afptype -p SHK -q $imageToolsDir/MOUNTIT.SHK |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|  |  | ||||||
|         if [[ ! $autoAnswerYes ]]; then |  | ||||||
|             echo |  | ||||||
|             echo "Do you want to download and install utilities for working with" |  | ||||||
|             echo -n "disk images and archive files in ProDOS 8? " |  | ||||||
|             read |  | ||||||
|         fi |  | ||||||
|         if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|      |  | ||||||
|             echo "A2SERVER: Downloading ProDOS 8 disk image utilities..." |  | ||||||
|  |  | ||||||
|             mkdir -p $diskToolsP8Dir |  | ||||||
|      |  | ||||||
|             echo -n "ShrinkIt 3.4" |  | ||||||
|             # get ShrinkIt 3.4 (for ProDOS 8) |  | ||||||
|             if [[ -f $diskToolsP8Dir/SHRINKIT ]]; then |  | ||||||
|                 echo " is already installed." |  | ||||||
|             else |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 wget -qO shrinkit.sdk http://web.archive.org/web/20131031160750/http://www.nulib.com/library/shrinkit.sdk |  | ||||||
|                 [[ ! -f shrinkit.sdk ]] && wget -qO shrinkit.sdk appleii.ivanx.com/a2server/files/shrinkit.sdk |  | ||||||
|                 nulib2 -xs shrinkit.sdk > /dev/null |  | ||||||
|                 cppo -s -ad SHRINKIT /SHRINKIT/SHRINKIT $diskToolsP8Dir 2> /dev/null |  | ||||||
|                 afpsync -v $sharepath > /dev/null |  | ||||||
|             fi |  | ||||||
|          |  | ||||||
|             echo -n "DSK2FILE 5.8" |  | ||||||
|             # get DSK2FILE (for ProDOS 8) |  | ||||||
|             if [[ -f $diskToolsP8Dir/DSK2FILE ]]; then |  | ||||||
|                 echo " is already installed." |  | ||||||
|             else |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 wget -q -O dsk2file.shk http://www.dwheeler.com/6502/oneelkruns/dsk2file.zip |  | ||||||
|                 nulib2 -x -s dsk2file.shk > /dev/null |  | ||||||
|                 cp -p DSK2FILE58 $diskToolsP8Dir/DSK2FILE |  | ||||||
|                 afpsync -v $sharepath > /dev/null |  | ||||||
|                 afptype -p SYS -q $diskToolsP8Dir/DSK2FILE |  | ||||||
|             fi |  | ||||||
|      |  | ||||||
|             echo -n "Apple System Utilities 3.1" |  | ||||||
|             if [[ -f $diskToolsP8Dir/SYSUTIL ]]; then |  | ||||||
|                 echo " is already installed." |  | ||||||
|             else |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 wget -qO Apple_II_System_Disk_3.2.sea.bin http://archive.org/download/download.info.apple.com.2012.11/download.info.apple.com.2012.11.zip/download.info.apple.com%2FApple_Support_Area%2FApple_Software_Updates%2FEnglish-North_American%2FApple_II%2FApple_II_Supplemental%2FApple_II_System_Disk_3.2.sea.bin |  | ||||||
|                 unar -k skip Apple_II_System_Disk_3.2.sea.bin &> /dev/null |  | ||||||
|                 truncate -s 819284 'Apple II System Disk 3.2.sea' |  | ||||||
|                 dd if='Apple II System Disk 3.2.sea' of=A2SYSDISK32.HDV bs=84 skip=1 2> /dev/null |  | ||||||
|                 cppo -s -ad A2SYSDISK32.HDV /UTILITIES/SYSUTIL.SYSTEM $diskToolsP8Dir/SYSUTIL 2> /dev/null |  | ||||||
|                 cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.0 $diskToolsP8Dir 2> /dev/null |  | ||||||
|                 cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.1 $diskToolsP8Dir 2> /dev/null |  | ||||||
|                 cppo -s -ad A2SYSDISK32.HDV /UTILITIES/UTIL.2 $diskToolsP8Dir 2> /dev/null |  | ||||||
|                 afpsync -v $sharepath > /dev/null |  | ||||||
|             fi |  | ||||||
|      |  | ||||||
|         fi |  | ||||||
|  |  | ||||||
|         if [[ ! $autoAnswerYes ]]; then |  | ||||||
|             echo |  | ||||||
|             echo "Do you want to download serial communications software for" |  | ||||||
|             echo -n "GS/OS and ProDOS 8? " |  | ||||||
|             read |  | ||||||
|         fi |  | ||||||
|         if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|      |  | ||||||
|             echo "A2SERVER: Downloading communications software..." |  | ||||||
|  |  | ||||||
|             mkdir -p $commDir |  | ||||||
|      |  | ||||||
|             echo -n "Spectrum" |  | ||||||
|             # get Spectrum |  | ||||||
|             if [[ -f $commDir/SPECTRUM/SPECTRUM.HDV ]]; then |  | ||||||
|                 echo " is already installed." |  | ||||||
|             else |  | ||||||
|                 mkdir -p $spectrumDir |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 wget -qO- http://www.speccie.co.uk/speccie/software/spectrum.2mg | dd bs=64 skip=1 of=$spectrumDir/SPECTRUM.HDV 2> /dev/null |  | ||||||
|                 wget -qO- http://www.speccie.co.uk/speccie/software/spectrum_extras.2mg | dd bs=64 skip=1 of=$spectrumDir/EXTRAS.HDV 2> /dev/null |  | ||||||
|                 wget -qO- http://www.speccie.co.uk/speccie/software/spectrum_sounds.2mg | dd bs=64 skip=1 of=$spectrumDir/SOUNDS.HDV 2> /dev/null |  | ||||||
|                 wget -qO- http://www.speccie.co.uk/speccie/software/spectrum_manuals.2mg | dd bs=64 skip=1 of=$spectrumDir/MANUALS.HDV 2> /dev/null |  | ||||||
|                 afpsync -v $gsosDir > /dev/null |  | ||||||
|             fi |  | ||||||
|  |  | ||||||
|             echo -n "ProTERM and Z-Link" |  | ||||||
|             # get A2CLOUD disk and copy from there |  | ||||||
|             if [[ -f $commDir/PROTERM/PROTERM ]]; then |  | ||||||
|                 echo " are already installed." |  | ||||||
|             else |  | ||||||
|                 mkdir -p $protermDir |  | ||||||
|                 mkdir -p $protermDir/.AppleDouble |  | ||||||
|                 mkdir -p $zlinkDir |  | ||||||
|                 mkdir -p $zlinkDir/.AppleDouble |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot |  | ||||||
|                 wget -qO A2CLOUD.HDV http://ivanx.com/a2cloud/files/A2CLOUD.HDV |  | ||||||
|                 cppo -ad A2CLOUD.HDV . > /dev/null |  | ||||||
|                 cd A2CLOUD |  | ||||||
|                 mv *PT3* *PROTERM* $protermDir |  | ||||||
|                 mv Z.LINK $zlinkDir |  | ||||||
|                 cd .AppleDouble |  | ||||||
|                 mv *PT3* *PROTERM* $protermDir/.AppleDouble |  | ||||||
|                 mv Z.LINK $zlinkDir/.AppleDouble |  | ||||||
|                 afpsync -v $gsosDir > /dev/null |  | ||||||
|             fi             |  | ||||||
|  |  | ||||||
|             echo -n "ADTPro and VSDRIVE" |  | ||||||
|             if [[ -f $commDir/ADTPRO/ADTPRO ]]; then |  | ||||||
|                 echo " are already installed." |  | ||||||
|             else |  | ||||||
|                 mkdir -p $adtproDir |  | ||||||
|                 mkdir -p $adtproDir/.AppleDouble |  | ||||||
|                 echo |  | ||||||
|                 cd /tmp/netboot/A2CLOUD |  | ||||||
|                 mv *ADTPRO* *VEDRIVE* *VSDRIVE* $adtproDir |  | ||||||
|                 cd .AppleDouble |  | ||||||
|                 mv *ADTPRO* *VEDRIVE* *VSDRIVE* $adtproDir/.AppleDouble |  | ||||||
|                 afpsync -v $gsosDir > /dev/null |  | ||||||
|             fi             |  | ||||||
|  |  | ||||||
|         fi |  | ||||||
|              |  | ||||||
|         # clean up |  | ||||||
|         cd |  | ||||||
|         [[ -d /tmp/netboot ]] && rm -rf /tmp/netboot |  | ||||||
|         [[ -d ~/GNUstep ]] && rm -rf ~/GNUstep |  | ||||||
|      |  | ||||||
|         # rock and roll! |  | ||||||
|         echo |  | ||||||
|          |  | ||||||
|         echo |  | ||||||
|         if (( $gsosInstall )); then |  | ||||||
|             echo "GS/OS network boot (for registered user and Guest) and" |  | ||||||
|         fi |  | ||||||
|         echo "ProDOS 8 network boot (for Guest only) is now configured." |  | ||||||
|         echo "See http://appleii.ivanx.com/a2server for info using it."  |  | ||||||
|      |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     if [[ ! $autoAnswerYes ]]; then |  | ||||||
|         echo |  | ||||||
|         echo "Do you want to download the patch required for using" |  | ||||||
|         echo -n "a Farallon LocalTalk-to-Ethernet bridge with GS/OS? " |  | ||||||
|         read |  | ||||||
|     fi |  | ||||||
|     if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|         echo "A2SERVER: Downloading Farallon bridge patch..." |  | ||||||
|         wget -O /tmp/FARALLON.PO appleii.ivanx.com/a2server/files/FARALLON.B1.PO &> /dev/null |  | ||||||
|         if [[ -d $gsosDir/SYSTEM/SYSTEM.SETUP ]]; then |  | ||||||
|             cppo -s -ad /tmp/FARALLON.PO /ATALKPATCH/ATALKIRQ $gsosDir/SYSTEM/SYSTEM.SETUP &> /dev/null |  | ||||||
|             echo |  | ||||||
|             echo "A2SERVER: The Farallon bridge patch is installed." |  | ||||||
|         else |  | ||||||
|             cppo -s -ad /tmp/FARALLON.PO /ATALKPATCH/ATALKIRQ $gsosDir &> /dev/null |  | ||||||
|             echo |  | ||||||
|             echo "On your Apple IIgs, copy the file ATALKIRQ in /A2SHARED to the" |  | ||||||
|             echo "SYSTEM.SETUP folder of the SYSTEM folder of your GSOS startup disk," |  | ||||||
|             echo "or, if you can't, download the patch from the A2SERVER web site." |  | ||||||
|         fi |  | ||||||
|         echo |  | ||||||
|         echo "Note: Farallon bridges can only be used in GS/OS (with this patch)" |  | ||||||
|         echo "and Apple IIe computers. Apple IIgs computers which network boot" |  | ||||||
|         echo "directly into ProDOS 8 will freeze after a few minutes." |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
| fi |  | ||||||
| @@ -1,95 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # Set up A2SERVER to support Samba (Windows File Sharing) |  | ||||||
| # this script can also be used if new shares are introduced |  | ||||||
|  |  | ||||||
| [[ -f /tmp/a2server-autoAnswerYes ]] && autoAnswerYes=1 || autoAnswerYes= |  | ||||||
|  |  | ||||||
| if [[ ! $autoAnswerYes || -f /tmp/a2server-setupWindowsSharing ]]; then |  | ||||||
|  |  | ||||||
|     if [[ ! $autoAnswerYes ]]; then |  | ||||||
|         echo |  | ||||||
|         echo -n "Should Windows computers be able to connect to A2SERVER? " |  | ||||||
|         read |  | ||||||
|     fi |  | ||||||
|     if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|      |  | ||||||
|         echo "A2SERVER: Setting up Windows file sharing..." |  | ||||||
|         sudo true |  | ||||||
|      |  | ||||||
|         if [[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]]; then |  | ||||||
|             [[ -f /etc/init/smbd.conf.off ]] && sudo mv /etc/init/smbd.conf.off /etc/init/smbd.conf |  | ||||||
|             [[ -f /etc/init/nmbd.conf.off ]] && sudo mv /etc/init/nmbd.conf.off /etc/init/nmbd.conf |  | ||||||
|             [[ ! -f /etc/init/smbd.conf || ! -f /etc/init/nmbd.conf ]] && installSamba=1 |  | ||||||
|         else |  | ||||||
|             sudo update-rc.d samba defaults &> /dev/null |  | ||||||
|             [[ ! -f /etc/init.d/samba ]] && installSamba=1 |  | ||||||
|         fi |  | ||||||
|      |  | ||||||
|         if (( $installSamba )); then |  | ||||||
|             if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then |  | ||||||
|                 # prepare for installing packages |  | ||||||
|                 sudo apt-get -y update |  | ||||||
|                 touch /tmp/a2server-packageReposUpdated |  | ||||||
|             fi |  | ||||||
|      |  | ||||||
|             sudo apt-get -y install samba |  | ||||||
|             [[ -f /usr/bin/smbpasswd ]] || sudo apt-get -y install samba-common-bin |  | ||||||
|             sudo apt-get clean |  | ||||||
|         fi |  | ||||||
|      |  | ||||||
|         if [[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]]; then |  | ||||||
|             sudo initctl start smbd &> /dev/null |  | ||||||
|             sudo initctl start nmbd &> /dev/null |  | ||||||
|         else |  | ||||||
|             sudo /etc/init.d/samba start &> /dev/null |  | ||||||
|         fi |  | ||||||
|      |  | ||||||
|         workgroup=$(grep -o "^   workgroup = .*$" /etc/samba/smb.conf 2> /dev/null | cut -c 16-) |  | ||||||
|         [[ $workgroup ]] || workgroup="WORKGROUP" |  | ||||||
|         if [[ ! $autoAnswerYes ]]; then |  | ||||||
|             echo |  | ||||||
|             echo "Enter workgroup name (or press return for '${workgroup}'): " |  | ||||||
|             read |  | ||||||
|             [[ $REPLY ]] && workgroup=$REPLY |  | ||||||
|         fi |  | ||||||
|         sudo sed -i 's/^   workgroup = .*$/   workgroup = '$workgroup'/' /etc/samba/smb.conf 2> /dev/null |  | ||||||
|         sudo sed -i 's/^#   security = user/   security = user/' /etc/samba/smb.conf 2> /dev/null |  | ||||||
|          |  | ||||||
|         grep ^/media /usr/local/etc/netatalk/AppleVolumes.default | cut -d" " -f2 \ |  | ||||||
|         | while read sharename; do |  | ||||||
|             if [[ $(grep $sharename /etc/samba/smb.conf) ]]; then |  | ||||||
|                 echo "A2SERVER: $sharename is already set up for Windows file sharing." |  | ||||||
|             else |  | ||||||
|                 echo "[$sharename]" | sudo tee -a /etc/samba/smb.conf > /dev/null |  | ||||||
|                 echo "    path = /media/A2SHARED/$sharename" | sudo tee -a /etc/samba/smb.conf > /dev/null |  | ||||||
|                 echo "    browsable = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null |  | ||||||
|                 echo "    guest ok = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null |  | ||||||
|                 echo "    read only = no" | sudo tee -a /etc/samba/smb.conf > /dev/null |  | ||||||
|                 echo "    create mask = 0666" | sudo tee -a /etc/samba/smb.conf > /dev/null |  | ||||||
|                 echo "    force user = $USER" | sudo tee -a /etc/samba/smb.conf > /dev/null |  | ||||||
|                 echo "A2SERVER: $sharename has been set up for Windows file sharing." |  | ||||||
|             fi |  | ||||||
|         done |  | ||||||
|          |  | ||||||
|         echo |  | ||||||
|         echo "A2SERVER: Setting Windows file sharing password to 'apple2'." |  | ||||||
|         echo -e 'apple2\napple2' | sudo smbpasswd -s -a $USER |  | ||||||
|  |  | ||||||
|         echo |  | ||||||
|         echo "A2SERVER: Windows file sharing is now running." |  | ||||||
|     else |  | ||||||
|         if [[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]]; then |  | ||||||
|             sudo initctl stop smbd &> /dev/null |  | ||||||
|             sudo initctl stop nmbd &> /dev/null |  | ||||||
|             [[ -f /etc/init/smbd.conf ]] && sudo mv /etc/init/smbd.conf /etc/init/smbd.conf.off |  | ||||||
|             [[ -f /etc/init/nmbd.conf ]] && sudo mv /etc/init/nmbd.conf /etc/init/nmbd.conf.off |  | ||||||
|         else |  | ||||||
|             sudo /etc/init.d/samba stop &> /dev/null |  | ||||||
|             sudo update-rc.d -f samba remove &> /dev/null |  | ||||||
|         fi |  | ||||||
|         echo "A2SERVER: Windows file sharing has been turned off." |  | ||||||
|     fi |  | ||||||
|      |  | ||||||
|     echo |  | ||||||
| fi |  | ||||||
| @@ -1,105 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # --- Ubuntu Server console optimizaton (optional) |  | ||||||
|  |  | ||||||
| # This script helps when running on the Linux console within the VM. |  | ||||||
|  |  | ||||||
| echo |  | ||||||
|  |  | ||||||
| userPw=$(sudo grep "^$USER" /etc/shadow | cut -f 2 -d ':') |  | ||||||
| [[ $userPw == "$(echo 'apple2' | perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isApple2Pw=1 || isApple2Pw= |  | ||||||
| [[ $userPw == "$(echo 'raspberry' | perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isRaspberryPw=1 || isRaspberryPw= |  | ||||||
|  |  | ||||||
| password="your password" |  | ||||||
| [[ $isApple2Pw ]] && password="'apple2'" |  | ||||||
| [[ $isRaspberryPw ]] && password="'raspberry'" |  | ||||||
|  |  | ||||||
| isDebian= |  | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1-2 < /etc/debian_version) == "7." ) && ( $(uname -m) == "i686" ) ]] && isDebian=1 |  | ||||||
|  |  | ||||||
| if [[ $isDebian ]]; then |  | ||||||
|     if { lspci 2> /dev/null | grep -q VirtualBox; }; then |  | ||||||
|         echo "A2SERVER: Disabling VirtualBox console screen blanking..." |  | ||||||
|         sudo sed -i 's/^BLANK_DPMS=off/BLANK_DPMS=on/' /etc/kbd/config |  | ||||||
|         sudo sed -i 's/^BLANK_TIME=[^0].$/BLANK_TIME=0/' /etc/kbd/config |  | ||||||
|         sudo /etc/init.d/kbd restart &> /dev/null |  | ||||||
|         sudo /etc/init.d/console-setup restart &> /dev/null |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # check that we're on Ubuntu |  | ||||||
| if [[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]]; then |  | ||||||
|  |  | ||||||
|     # don't do any of this if we're logged in via SSH |  | ||||||
|     if [[ $SSH_CLIENT || $REMOTEHOST ]]; then |  | ||||||
|         echo "A2SERVER: Logged in via SSH,not performing console optimization." |  | ||||||
|         echo "Run setup from the console if you want to optimize the console." |  | ||||||
|     else |  | ||||||
|          |  | ||||||
|         # if we've already done this stuff, don't do it again |  | ||||||
|         if [[ ! -x /etc/update-motd.d/10-help-text ]]; then |  | ||||||
|          |  | ||||||
|             echo "A2SERVER: Ubuntu console has already been optimized." |  | ||||||
|         else |  | ||||||
|             echo "Ubuntu console optimization for use in a virtual machine will:" |  | ||||||
|             echo "- show the default username/password on the login screen" |  | ||||||
|             echo "- remove the documentation URL and system statistics shown after login" |  | ||||||
|             echo "- ensure the screen clears before showing the login prompt" |  | ||||||
|             echo "- prevent the screen from dimming after 10 minutes (once logged in)" |  | ||||||
|             echo "- eliminate a harmless but annoying startup error about piix_smbus" |  | ||||||
|             echo "- fix an Ubuntu 10.04 issue with slow scrolling" |  | ||||||
|             echo |  | ||||||
|             if [[ ! $autoAnswerYes ]]; then |  | ||||||
|                 echo -n "Do you want to optimize the Ubuntu console? " |  | ||||||
|                 read |  | ||||||
|             fi |  | ||||||
|             if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|          |  | ||||||
|                 echo "A2SERVER: Optimizing console..." |  | ||||||
|                  |  | ||||||
|                 # remind the user how to log in (we're going for functionality here, not security) |  | ||||||
|                 if [[ ! $(grep $USER\/$password /etc/issue) ]]; then |  | ||||||
|                     sudo sed -i '/^Log in with.*$/d' /etc/issue |  | ||||||
|                     echo "Log in with '$USER' / '$password'." | sudo tee -a /etc/issue > /dev/null |  | ||||||
|                     echo | sudo tee -a /etc/issue > /dev/null |  | ||||||
|                 fi |  | ||||||
|                  |  | ||||||
|                 # If after logging in, you don't like the documentation URL and |  | ||||||
|                 # system info (or an error about it) being displayed, type: |  | ||||||
|                 sudo chmod -x /etc/update-motd.d/10-help-text |  | ||||||
|                 sudo chmod -x /etc/update-motd.d/50-landscape-sysinfo |  | ||||||
|          |  | ||||||
|                 # If the screen doesn't clear for login after the boot messages, and |  | ||||||
|                 # you'd like it to, type: |  | ||||||
|                 sudo sed -i 's/X_DEFAULT=""/X_DEFAULT="quiet"/g' /etc/default/grub |  | ||||||
|                 sudo update-grub |  | ||||||
|                  |  | ||||||
|                 # If you see a piix4_smbus error on startup, it is harmless, but if you |  | ||||||
|                 # want to eliminate it, type: |  | ||||||
|                 echo -e '\nblacklist i2c_piix4' \ |  | ||||||
|                 | sudo tee -a /etc/modprobe.d/blacklist.conf > /dev/null |  | ||||||
|                 sudo update-initramfs -u -k all |  | ||||||
|                  |  | ||||||
|                 # If you want to prevent the Ubuntu screen from going blank after ten |  | ||||||
|                 # minutes of inactivity (once you are logged in), type: |  | ||||||
|                 echo -e \ |  | ||||||
|                 '\n[[ $SSH_CLIENT || $REMOTEHOST ]] || setterm -blank 0 -powersave off -powerdown 0' \ |  | ||||||
|                 | sudo tee -a /etc/profile > /dev/null |  | ||||||
|                 setterm -blank 0 -powersave off -powerdown 0 |  | ||||||
|                  |  | ||||||
|                 # (note: These next lines addresses an issue only for Ubuntu 10.04.) |  | ||||||
|                 # Type "ps aux" and press return. If you see slow text scrolling, type: |  | ||||||
|                 if [[ "$(lsb_release -rs 2> /dev/null)" == "10.04" ]]; then |  | ||||||
|                     echo -e '\nblacklist vga16fb' \ |  | ||||||
|                     | sudo tee -a /etc/modprobe.d/blacklist-framebuffer.conf > /dev/null |  | ||||||
|                     if [[ ! $SSH_CLIENT ]]; then |  | ||||||
|                         echo "Restarting now is recommended. To resume setup, log back" |  | ||||||
|                         echo -n "in, press up-arrow, and press return. Restart now? " |  | ||||||
|                         read; R=${REPLY:0:1} |  | ||||||
|                         [[ $R != "y" ]] && [[ $R != "Y" ]] || sudo shutdown -r now |  | ||||||
|                     fi |  | ||||||
|                 fi |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
| @@ -1,86 +0,0 @@ | |||||||
| # A2SERVER aliases: |  | ||||||
|  |  | ||||||
|  |  | ||||||
| alias a2server-help="more /usr/local/etc/a2server-help.txt" |  | ||||||
| alias a2server-setup="wget -q -O /tmp/a2server-setup appleii.ivanx.com/a2server/setup/; source /tmp/a2server-setup" |  | ||||||
|  |  | ||||||
| alias a2server-version="cat /usr/local/etc/A2SERVER-version" |  | ||||||
| alias a2server-update="wget -q -O /tmp/a2server-update appleii.ivanx.com/a2server/update/; source /tmp/a2server-update" |  | ||||||
|  |  | ||||||
| alias system-shutdown='sudo shutdown -h now' |  | ||||||
| alias system-restart='sudo shutdown -r now' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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?"' |  | ||||||
| alias raspbian-update='wget -qO /tmp/raspbian-update ivanx.com/a2server/files/raspbian-update.txt; source /tmp/raspbian-update' |  | ||||||
| alias rasppleii-update='raspbian-update a2cloud a2server' |  | ||||||
|  |  | ||||||
| alias welcome-message-edit='[[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]] && motd=/etc/issue || motd=/etc/motd; sudo nano $motd' |  | ||||||
|  |  | ||||||
| alias showip='ifconfig eth0 | grep "inet\ addr" | cut -d: -f2 | cut -d" " -f1' |  | ||||||
| alias showmac='ifconfig eth0 | grep "HWaddr" | cut -dH -f2 | cut -c7-23' |  | ||||||
| alias showip-wifi='ifconfig wlan0 | grep "inet\ addr" | cut -d: -f2 | cut -d" " -f1' |  | ||||||
| alias showmac-wifi='ifconfig wlan0 | grep "HWaddr" | cut -dH -f2 | cut -c7-23' |  | ||||||
| alias ifreset='sudo rm /etc/udev/rules.d/70-persistent-net.rules; echo Interfaces removed. You should system-restart now.' |  | ||||||
|  |  | ||||||
| alias netatalk-stop="sudo /etc/init.d/netatalk stop; bonjour-off" |  | ||||||
| alias netatalk-start="sudo /etc/init.d/netatalk start; bonjour-on" |  | ||||||
| alias netatalk-restart="sudo /etc/init.d/netatalk restart; bonjour-on" |  | ||||||
| alias netatalk-off='sudo /etc/init.d/netatalk stop; bonjour-off; sudo update-rc.d -f netatalk remove &> /dev/null' |  | ||||||
| alias netatalk-on='sudo update-rc.d netatalk defaults &> /dev/null; bonjour-on; sudo /etc/init.d/netatalk restart' |  | ||||||
|  |  | ||||||
| alias bonjour-off="sudo mv /etc/avahi/services/afpd.service /etc/avahi/services/afpd.service_disabled &> /dev/null" |  | ||||||
| alias bonjour-on="sudo mv /etc/avahi/services/afpd.service_disabled /etc/avahi/services/afpd.service &> /dev/null" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| alias netatalk-router-on='sudo sed -i '"'"'s/^eth0.*$/eth0 -router -phase 2 -net 1 -zone "A2SERVER"/'"'"' /usr/local/etc/netatalk/atalkd.conf; sudo sed -i '"'"'s/^wlan0.*$/wlan0 -router -phase 2 -net 1 -zone "A2SERVER"/'"'"' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' |  | ||||||
| alias netatalk-router-off='sudo sed -i '"'"'s/^eth0.*$/eth0/'"'"' /usr/local/etc/netatalk/atalkd.conf; sudo sed -i '"'"'s/^wlan0.*$/wlan0/'"'"' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| alias netatalk-eth='sudo sed -i 's/^wlan0/eth0/' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' |  | ||||||
| alias netatalk-wifi='sudo sed -i 's/^eth0/wlan0/' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| alias appletalk-off='sudo sed -i "s/ATALKD_RUN=yes/ATALKD_RUN=no/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart' |  | ||||||
| alias appletalk-on='sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| NETATALK="/usr/local/etc/netatalk" |  | ||||||
| A2FILES="/media/A2SHARED/A2FILES" |  | ||||||
| GSFILES="/media/A2SHARED/GSFILES" |  | ||||||
|  |  | ||||||
| alias netboot-gsos="mkatinit -gs -d -f" |  | ||||||
| alias netboot-gsos-guest="mkatinit -gs -d -f guest" |  | ||||||
| alias netboot-p8="mkatinit -d -f" |  | ||||||
| alias netboot-p8-guest="mkatinit -d -f guest" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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; sudo /etc/init.d/netatalk restart" |  | ||||||
| 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; sudo /etc/init.d/netatalk restart" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| alias samba-off='[[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]] && { sudo initctl stop smbd; sudo initctl stop nmbd; [[ -f /etc/init/smbd.conf ]] && sudo mv /etc/init/smbd.conf /etc/init/smbd.conf.off; [[ -f /etc/init/nmbd.conf ]] && sudo mv /etc/init/nmbd.conf /etc/init/nmbd.conf.off; } || { sudo /etc/init.d/samba stop; sudo update-rc.d -f samba remove &> /dev/null; }' |  | ||||||
| alias samba-on='[[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]] && { [[ -f /etc/init/smbd.conf.off ]] && sudo mv /etc/init/smbd.conf.off /etc/init/smbd.conf; [[ -f /etc/init/nmbd.conf.off ]] && sudo mv /etc/init/nmbd.conf.off /etc/init/nmbd.conf; sudo initctl start smbd; sudo initctl start nmbd; } || { sudo update-rc.d samba defaults &> /dev/null; sudo /etc/init.d/samba restart; }' |  | ||||||
| alias samba-stop='[[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]] && { sudo initctl stop smbd; sudo initctl stop nmbd; } || { sudo /etc/init.d/samba stop; }' |  | ||||||
| alias samba-start='[[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]] && { sudo initctl start smbd; sudo initctl start nmbd; } || { sudo /etc/init.d/samba start; }' |  | ||||||
| alias samba-restart='[[ $(lsb_release -d 2> /dev/null | grep Ubuntu) ]] && { sudo initctl restart smbd; sudo initctl restart nmbd; } || { sudo /etc/init.d/samba restart; }' |  | ||||||
|  |  | ||||||
| alias gsfiles-share="sudo sed -i 's/^\/media\/A2SHARED\/GSFILES\ GSFILES options:prodos/#share1/' /usr/local/etc/netatalk/AppleVolumes.default" |  | ||||||
| alias gsfiles-unshare="sudo sed -i 's/^#share1/\/media\/A2SHARED\/GSFILES\ GSFILES options:prodos/' /usr/local/etc/netatalk/AppleVolumes.default; [[ -d /media/A2SHARED/GSFILES ]] || mkdir /media/A2SHARED/GSFILES" |  | ||||||
| alias a2files-share="sudo sed -i 's/^\/media\/A2SHARED\/A2FILES\ A2FILES options:prodos\ casefold:toupper/#share2/' /usr/local/etc/netatalk/AppleVolumes.default" |  | ||||||
| alias a2files-unshare="sudo sed -i 's/^#share2/\/media\/A2SHARED\/A2FILES\ A2FILES options:prodos\ casefold:toupper/' /usr/local/etc/netatalk/AppleVolumes.default; [[ -d /media/A2SHARED/A2FILES ]] || mkdir /media/A2SHARED/A2FILES" |  | ||||||
|  |  | ||||||
| alias showalias="alias | cut -d= -f 1 | cut -d' ' -f2 | more" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # |  | ||||||
| @@ -1,86 +0,0 @@ | |||||||
| A2SERVER commands: |  | ||||||
|   (note: new commands may be added; use a2server-setup to refresh) |  | ||||||
|  |  | ||||||
| a2server-help: show this list of commands |  | ||||||
| a2server-setup: set up network boot, Windows access, Farallon fix, |  | ||||||
|     refresh command list |  | ||||||
| a2server-version: see installed version of A2SERVER |  | ||||||
| a2server-update: check for update to A2SERVER |  | ||||||
|  |  | ||||||
| system-shutdown: shut down the server |  | ||||||
| system-restart: shut down and restart the server |  | ||||||
|  |  | ||||||
|  Raspberry Pi commands, if you're using one: |  | ||||||
| raspi-config: utilize all space on RPi SD card & other options |  | ||||||
| raspbian-update : update Raspbian operating system |  | ||||||
| rasppleii-update : update Raspbian OS, A2CLOUD, A2SERVER, Apple II Pi |  | ||||||
|  |  | ||||||
| welcome-message-edit: change the welcome message |  | ||||||
|  |  | ||||||
| showip: show the current ethernet IP address of the server |  | ||||||
| showmac: show the MAC (Ethernet hardware) address of the server |  | ||||||
| showip-wifi: show the current wifi IP address of the server |  | ||||||
| showmac-wifi: show the MAC (wifi hardware) address of the server |  | ||||||
| ifreset: reset all network interfaces (requires restart)  |  | ||||||
|  |  | ||||||
| netatalk-stop: stop the netatalk service until reboot |  | ||||||
| netatalk-start: start the netatalk service |  | ||||||
| netatalk-restart: restart the netatalk service |  | ||||||
| netatalk-off: disable the netatalk service (even after reboot) |  | ||||||
| netatalk-on: enable the netatalk service |  | ||||||
|  |  | ||||||
| bonjour-off: disable advertisement of shared folders to OS X |  | ||||||
| bonjour-on : enable advertisement of shared folders to OS X |  | ||||||
|   (these are automatically set by the netatalk commands above) |  | ||||||
|  |  | ||||||
| netatalk-router-on: use netatalk in router mode (default) |  | ||||||
| netatalk-router-off: use netatalk in node mode |  | ||||||
|   (use if there is an AppleTalk router such as a GatorBox present) |  | ||||||
|  |  | ||||||
| netatalk-eth: use wired ethernet interface for netatalk (default) |  | ||||||
| netatalk-wifi: use wifi interface for netatalk |  | ||||||
|     note: if an interface isn't available, netatalk will be reset with |  | ||||||
|     router mode off; use "netatalk-router-on" to correct this if needed |  | ||||||
|  |  | ||||||
| appletalk-off: disable AppleTalk networking (even after reboot) |  | ||||||
| appletalk-on : enable AppleTalk networking |  | ||||||
|  |  | ||||||
| environment variables: |  | ||||||
| $NETATALK: directory containing netatalk configuration files |  | ||||||
| $A2FILES : directory containing A2FILES shared volume |  | ||||||
| $GSFILES : directory containing GSFILES shared volume |  | ||||||
|  |  | ||||||
| netboot-gsos: set the current user to netboot into GS/OS (default) |  | ||||||
| netboot-gsos-guest: set guests to netboot into GS/OS |  | ||||||
| netboot-p8: set the current user to netboot into ProDOS 8 |  | ||||||
| netboot-p8-guest: set guests to netboot into ProDOS 8 (default) |  | ||||||
|   note: when a IIgs is set to network boot into GS/OS, using the Network |  | ||||||
|   control panel or the NETBOOT.GSOS utility, guests will behave like |  | ||||||
|   registered users, and ignore the netboot setting of the guest user |  | ||||||
|    |  | ||||||
| guest-off: disallow guest access to A2SERVER |  | ||||||
| guest-on: allow guest access to A2SERVER (default) |  | ||||||
|   note: by default, Guest access is the only way to network boot into |  | ||||||
|   ProDOS 8. For registered user boot into ProDOS 8, type "netboot-p8" |  | ||||||
|  |  | ||||||
| samba-off: disable Windows file sharing (even after reboot) |  | ||||||
| samba-on: enable Windows file Sharing |  | ||||||
| samba-stop: stop Windows file sharing until reboot |  | ||||||
| samba-start: start Windows file sharing |  | ||||||
| samba-restart: stop and restart Windows file sharing |  | ||||||
|  |  | ||||||
| gsfiles-share: disable the GSFILES shared volume |  | ||||||
| gsfiles-unshare: enable the GSFILES shared volume |  | ||||||
| a2files-share: disable the A2FILES shared volume |  | ||||||
| a2files-unshare: enable the A2FILES shared volume |  | ||||||
|  |  | ||||||
| nulib2: create, extract, and work with NuFX (ShrinkIt) archive files |  | ||||||
| unar: extract other archive files (multiformat) |  | ||||||
| lsar: list contents of other archive files (multiformat) |  | ||||||
|  |  | ||||||
| afptype: set the ProDOS type/auxtype or Mac OS type/creator of a file |  | ||||||
| afpsync: register files introduced outside of AFP with netatalk |  | ||||||
| mkatinit: set up network boot configuration files |  | ||||||
| cppo: catalog and copy files from ProDOS image file (slow, but works) |  | ||||||
|   (add -h to show help for the above four commands, e.g. "afptype -h") |  | ||||||
|  |  | ||||||
| @@ -1,114 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # afpsync: updates .AppleDouble components of files on shared volumes |  | ||||||
|  |  | ||||||
| # this must be used if any files are copied to the shared volume via |  | ||||||
| # non-AFP methods (directly, via Samba, etc). |  | ||||||
|  |  | ||||||
| # usage: |  | ||||||
| # afpsync [-v] [shared volume path] |  | ||||||
| # |  | ||||||
| # -v will silently create a .volinfo file if none exists. |  | ||||||
| # If a path is specified, only that volume is synced; otherwise, all |  | ||||||
| # all paths in /media which appear in |  | ||||||
| # /usr/local/etc/netatalk/AppleVolumes.default are synced. |  | ||||||
|  |  | ||||||
| processPath () { |  | ||||||
|     if [[ ! -d $sharepath ]]; then |  | ||||||
|         echo "$sharepath does not exist." |  | ||||||
|     else |  | ||||||
|         volinfo="$sharepath/.AppleDesktop/.volinfo" |  | ||||||
|         if [[ ! -f $volinfo ]]; then |  | ||||||
|             if [[ ! $force ]]; then |  | ||||||
|                 echo "Cannot update AppleDouble files for volume $sharepath," |  | ||||||
|                 echo "because its .volinfo file does not exist. To create it, log" |  | ||||||
|                 echo "into the volume from an Apple II or Mac client computer," |  | ||||||
|                 echo "or use \"afpsync -v\"." |  | ||||||
|             else |  | ||||||
|                 if (( $1 )); then |  | ||||||
|                     mkvolinfo -f -c $sharepath |  | ||||||
|                 else |  | ||||||
|                     mkvolinfo -f $sharepath |  | ||||||
|                 fi |  | ||||||
|                 $0 $sharepath |  | ||||||
|             fi |  | ||||||
|         else |  | ||||||
|             IFS='' |  | ||||||
|             result=$(sudo dbd -r $sharepath | grep encoding) |  | ||||||
|             f=$(echo $result | wc -l) |  | ||||||
|             [[ $(echo $result | wc -w) == 0 ]] && f=0 |  | ||||||
|             [[ f -eq 1 && $(echo $result | grep APPLEDESKTOP) && $(grep MTOULOWER $sharepath/.AppleDesktop/.volinfo) ]] && (( f-- )) |  | ||||||
|             if (( f == 0 )); then |  | ||||||
|                 echo "AppleDouble files have been updated for volume $sharepath." |  | ||||||
|             else |  | ||||||
|                 [[ ! $renameLower ]] && echo "Could not update all files on volume $sharepath." |  | ||||||
|                 [[ ! $renameLower ]] && echo "Ensure filenames are all caps on volume $sharepath." |  | ||||||
|                 if [[ $showerrors ]]; then |  | ||||||
|                     echo $result \ |  | ||||||
|                     | while read LINE; do |  | ||||||
|                         [[ ! $(echo $LINE | grep APPLEDESKTOP) ]] && echo $LINE |  | ||||||
|                     done |  | ||||||
|                 elif [[ $renameLower ]]; then |  | ||||||
|                     echo $result \ |  | ||||||
|                     | while read LINE; do |  | ||||||
|                         if [[ ! $(echo $LINE | grep APPLEDESKTOP) ]]; then |  | ||||||
|                             filepath=$(echo $LINE | sed "s/^Bad\ encoding\ for\ '//" | sed s/\'//) |  | ||||||
|                             filename=${filepath##*/} |  | ||||||
|                             filedir=${filepath%/*} |  | ||||||
|                             mv $filepath $filedir/${filename^^} |  | ||||||
|                             echo "Renamed $filedir/${filename^^}." |  | ||||||
|                         fi |  | ||||||
|                     done |  | ||||||
|                     $0 $sharepath |  | ||||||
|                 else |  | ||||||
|                     echo "Use afpsync -e to see error details." |  | ||||||
|                     echo "Use afpsync -r to rename lowercase names to uppercase." |  | ||||||
|                 fi |  | ||||||
|             fi |  | ||||||
|             unset IFS |  | ||||||
|         fi |  | ||||||
|     fi |  | ||||||
| } |  | ||||||
|  |  | ||||||
| while [[ $1 == "-r" || $1 == "-e" || $1 = "-v" ]]; do |  | ||||||
|  |  | ||||||
|     if [[ $1 == "-v" ]]; then |  | ||||||
|         force=1 |  | ||||||
|         shift |  | ||||||
|     fi |  | ||||||
|      |  | ||||||
|     if [[ $1 == "-e" ]]; then |  | ||||||
|         showerrors=1 |  | ||||||
|         shift |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     if [[ $1 == "-r" ]]; then |  | ||||||
|         renameLower=1 |  | ||||||
|         shift |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
| done |  | ||||||
|  |  | ||||||
| if [[ ${1:0:1} == "-" ]]; then |  | ||||||
|     echo "Usage: afpsync [-e|-r] [-v] [shared volume path]" |  | ||||||
|     echo |  | ||||||
|     echo "-e: show error details" |  | ||||||
|     echo "-r: rename lowercase filenames to uppercase" |  | ||||||
|     echo "-v: create .volinfo file if none exists" |  | ||||||
|     echo "If no directory is specified, all found in" |  | ||||||
|     echo "  /usr/local/etc/netatalk/AppleVolumes.default are processed." |  | ||||||
|     echo |  | ||||||
| else |  | ||||||
|     sudo true |  | ||||||
|     if [[ $1 ]]; then |  | ||||||
|         sharepath=$(readlink -m $1) |  | ||||||
|         processPath |  | ||||||
|     else     |  | ||||||
|         grep ^/media /usr/local/etc/netatalk/AppleVolumes.default | \ |  | ||||||
|         while read line; do |  | ||||||
|             [[ $(echo $line | grep toupper) ]]; nocasefold=$? |  | ||||||
|             sharepath=$(echo $line | cut -d" " -f1) |  | ||||||
|             processPath nocasefold |  | ||||||
|         done |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
| @@ -1,498 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # 2-25-11: tested on 10.6.5 and Ubuntu 10.10. Final. |  | ||||||
|  |  | ||||||
| # to do: allow hex offsets |  | ||||||
|  |  | ||||||
| # These bash functions perform single-byte dec-hex-character conversions |  | ||||||
| # and file read/write operations, and hopefully work identically across |  | ||||||
| # different platforms. Each can operate by itself without the presence |  | ||||||
| # of the others. They have been tested on Mac OS X 10.6 and |  | ||||||
| # Ubuntu Linux 10.10. Your mileage may vary. |  | ||||||
|  |  | ||||||
| # You provide parameters to the functions as arguments, or alternatively |  | ||||||
| # standard in (for the functions which accept characters). Examples: |  | ||||||
| #   Write hex byte with value "F0" to offset 23 in file "myFile": |  | ||||||
| # writecharHex myFile 23 F0 |  | ||||||
| #   Write "ABCDE" to the beginning of file "myFile" |  | ||||||
| # echo "ABCDE" | writechars myFile |  | ||||||
|  |  | ||||||
| # For functions which output something (all but the write operations), |  | ||||||
| # you can call the functions with command substitution if you want to |  | ||||||
| # assign the output to a variable rather than display it. Examples: |  | ||||||
| #   Convert decimal value 65 to its hexadecimal equivalent: |  | ||||||
| # val=$(decToHex 65) |  | ||||||
| #   Get decimal value of the character/byte at offset 215 in "myFile": |  | ||||||
| # val=$(readcharDec "myFile" 215) |  | ||||||
|  |  | ||||||
| # For functions which convert to or from a character, 0-127 will be |  | ||||||
| # ASCII/UTF-8, while 128-255 will be system/locale/codepage dependent. |  | ||||||
| # In this context, a character is effectively the same as a byte. |  | ||||||
|  |  | ||||||
| # The functions return a non-zero exit status for invalid or missing |  | ||||||
| # arguments. If you don't need these checks, remove the lines |  | ||||||
| # above the comment "args are valid" (or as otherwise noted). |  | ||||||
| # The exit statuses are, generally: |  | ||||||
| #    0 = no error |  | ||||||
| #    8 = extraneous argument |  | ||||||
| #    9 = standard input is invalid |  | ||||||
| #   1x = missing required argument (e.g. 11 for missing argument 1) |  | ||||||
| #   2x = argument is invalid (e.g. 22 for invalid argument 2) |  | ||||||
| # any other exit status will originate from the final command in the |  | ||||||
| # function (e.g. dd, printf) |  | ||||||
|  |  | ||||||
| # For the functions which output chars (readchars, decToChar, and |  | ||||||
| # hexToChar), be aware that NUL (0) and trailing LF (10/0x0A) chars will |  | ||||||
| # be stripped when assigned to a variable, and cannot appear in an |  | ||||||
| # argument. To preserve them, pipe the output elsewhere, such as into |  | ||||||
| # charToDec, charToHex, writechars, or a command. (readcharDec and |  | ||||||
| # readcharHex handle these characters correctly.) |  | ||||||
|  |  | ||||||
| # questions/comments to ivan@ivanx.com |  | ||||||
|  |  | ||||||
| decToHex () { |  | ||||||
| # converts single-byte decimal value to hexadecimal equivalent |  | ||||||
| # arg: decimal value from 0-255 |  | ||||||
| # out: two-digit hex value from 00-FF |  | ||||||
| #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg |  | ||||||
|     [[ $1 ]] || return 11 |  | ||||||
|     [[ $2 ]] && return 8 |  | ||||||
|     [[ ( $(printf %d "$1" 2> /dev/null) == $1 ) \ |  | ||||||
|      && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 |  | ||||||
|     # args are valid |  | ||||||
|     printf %02X "$1" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| hexToDec () { |  | ||||||
| # converts single-byte hexadecimal value to decimal equivalent |  | ||||||
| # arg: two-digit hex value from 00-FF |  | ||||||
| # out: decimal value |  | ||||||
| #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg |  | ||||||
|     [[ $1 ]] || return 11 |  | ||||||
|     [[ $2 ]] && return 8 |  | ||||||
|     [[ ${#1} -eq 2 ]] || return 21 |  | ||||||
|     [[ $(printf %02X "0x$1" 2> /dev/null) == \ |  | ||||||
|      $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21 |  | ||||||
|     # args are valid |  | ||||||
|     printf %d "0x$1" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| charToDec () { |  | ||||||
| # converts single character to corresponding decimal value |  | ||||||
| # stdin OR arg: one character |  | ||||||
| #  [arg overrides stdin; stdin is required for NUL (0) or LF (0x0A)] |  | ||||||
| # out: decimal value from 0-255 |  | ||||||
| #exit: 8=extraneous arg, 9=invalid stdin, |  | ||||||
| #      11=missing stdin/arg, 21=invalid arg |  | ||||||
|     [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } |  | ||||||
|     [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } |  | ||||||
|     # arg/stdin is potentially valid (additional check below) |  | ||||||
|     charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" |  | ||||||
|     [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) |  | ||||||
|     # above line verifies that arg/stdin is valid |  | ||||||
|     [[ ${#charX} -ne 2 ]] && { echo -n 0; return 0; } |  | ||||||
|     echo -n "${charX:0:1}" | od -t u1 | \ |  | ||||||
|      head -1 | sed 's/[0\ ]*//' | tr -d ' \n' |  | ||||||
| } |  | ||||||
|  |  | ||||||
| charToHex () { |  | ||||||
| # converts single character to corresponding hexadecimal value |  | ||||||
| # stdin OR arg: one character |  | ||||||
| #  [arg overrides stdin; stdin is required for NUL (0) or LF (0x0A)] |  | ||||||
| # out: decimal value from 0-255 |  | ||||||
| #exit: 8=extraneous arg, 9=invalid stdin, |  | ||||||
| #      11=missing stdin/arg, 21=invalid arg |  | ||||||
|     [[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; } |  | ||||||
|     [[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; } |  | ||||||
|     # arg/stdin is potentially valid (additional check below) |  | ||||||
|     charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)" |  | ||||||
|     [[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 )) |  | ||||||
|     # above line verifies that stdin/arg is valid |  | ||||||
|     [[ ${#charX} -ne 2 ]] && { echo -n "00"; return 0; } |  | ||||||
|     printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \ |  | ||||||
|      head -1 | sed 's/[0\ ]*//' | tr -d ' \n') |  | ||||||
| } |  | ||||||
|  |  | ||||||
| decToChar () { |  | ||||||
| # converts single-byte decimal value to equivalent character |  | ||||||
| # arg: decimal number from 0-255 |  | ||||||
| # out: one character |  | ||||||
| #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg |  | ||||||
|     [[ $1 ]] || return 11 |  | ||||||
|     [[ $2 ]] && return 8 |  | ||||||
|     [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ |  | ||||||
|      && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 |  | ||||||
|     # args are valid |  | ||||||
|     echo -n -e "\x$(printf %02X "$1")" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| hexToChar () { |  | ||||||
| # converts single-byte hexadecimal value to corresponding character |  | ||||||
| # arg: two-digit hexadecimal number from 00-FF |  | ||||||
| # out: one character |  | ||||||
| #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg |  | ||||||
|     [[ $1 ]] || return 11 |  | ||||||
|     [[ $2 ]] && return 8 |  | ||||||
|     [[ ${#1} -eq 2 ]] || return 21 |  | ||||||
|     [[ $(printf %02X "0x$1" 2> /dev/null) == \ |  | ||||||
|      $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21 |  | ||||||
|     # args are valid |  | ||||||
|     echo -n -e "\x$1" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| readchars () { |  | ||||||
| # read one or more characters from a file |  | ||||||
| # arg1: filename |  | ||||||
| # arg2: (optional) offset (# of bytes to skip before reading) |  | ||||||
| # arg3: (optional) # of chars to read (default is until end of file) |  | ||||||
| #  out: sequence of characters |  | ||||||
| # exit: 8=extraneous arg, 11=missing arg1, |  | ||||||
| #       21=invalid arg1, 22=invalid arg2, 23=invalid arg3 |  | ||||||
|     [[ $1 ]] || return 11 |  | ||||||
|     [[ $4 ]] && return 8 |  | ||||||
|     [[ -f $1 ]] || return 21 |  | ||||||
|     [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ |  | ||||||
|      && ( $2 -ge 0 ) ]] || return 22; } |  | ||||||
|     [[ $3 ]] && { [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \ |  | ||||||
|      && ( $3 -ge 0 ) ]] || return 23; } |  | ||||||
|     # args are valid |  | ||||||
|     dd if="$1" bs=1 skip=$(($2)) $([[ $3 ]] && echo -n "count=$3") \ |  | ||||||
|      2> /dev/null |  | ||||||
| } |  | ||||||
|  |  | ||||||
| readcharDec () { |  | ||||||
| # read one character from file & convert to equivalent decimal value |  | ||||||
| # arg1: filename |  | ||||||
| # arg2: (optional) offset (# of bytes to skip before reading) |  | ||||||
| #  out: decimal value from 0-255 |  | ||||||
| # exit: 8=extraneous arg, 11=missing arg1, |  | ||||||
| #       21=invalid arg1, 22=invalid arg2 |  | ||||||
|     [[ $1 ]] || return 11 |  | ||||||
|     [[ $3 ]] && return 8 |  | ||||||
|     [[ -f $1 ]] || return 21 |  | ||||||
|     [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ |  | ||||||
|      && ( $2 -ge 0 ) ]] || return 22; } |  | ||||||
|     # args are valid |  | ||||||
|     charX="$(dd if="$1" bs=1 skip=$(($2)) \ |  | ||||||
|      count=1 2> /dev/null; echo -n X)" |  | ||||||
|     [[ ${#charX} -gt 1 ]] || { echo -n 0; return 0; } |  | ||||||
|     echo -n "${charX:0:1}" | od -t u1 | \ |  | ||||||
|      head -1 | sed 's/[0\ ]*//' | tr -d ' \n' |  | ||||||
| } |  | ||||||
|  |  | ||||||
| readcharHex () { |  | ||||||
| # read one character from file & convert to corresponding hex value |  | ||||||
| # arg1: filename |  | ||||||
| # arg2: (optional) offset (# of bytes to skip before reading) |  | ||||||
| #  out: two-digit hex value from 00-FF |  | ||||||
| # exit: 8=extraneous arg, 11=missing arg1, |  | ||||||
| #       21=invalid arg1, 22=invalid arg2 |  | ||||||
|     [[ $1 ]] || return 11 |  | ||||||
|     [[ $3 ]] && return 8 |  | ||||||
|     [[ -f $1 ]] || return 21 |  | ||||||
|     [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ |  | ||||||
|      && ( $2 -ge 0 ) ]] || return 22; } |  | ||||||
|     # args are valid |  | ||||||
|     charX="$(dd if="$1" bs=1 skip=$(($2)) \ |  | ||||||
|      count=1 2> /dev/null; echo -n X)" |  | ||||||
|     [[ ${#charX} -gt 1 ]] || { echo -n "00"; return 0; } |  | ||||||
|     printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \ |  | ||||||
|      head -1 | sed 's/[0\ ]*//' | tr -d ' \n') |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ### 2-15-11 above tested on OS X and Linux |  | ||||||
|  |  | ||||||
| writechars () { |  | ||||||
| # write one or more characters (bytes) to file |  | ||||||
| # arg1: filename |  | ||||||
| # arg2: (optional) offset (# of bytes to skip before writing) |  | ||||||
| # arg3 OR stdin: sequence of characters |  | ||||||
| #  [stdin required if writing NUL (0) or trailing LF (0x0A) chars] |  | ||||||
| #  out: nothing |  | ||||||
| # exit: 8=extraneous arg, 11=missing arg1, |  | ||||||
| #       13=missing stdin/arg3, 22=invalid arg2 |  | ||||||
|     [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } |  | ||||||
|     [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ |  | ||||||
|      ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } |  | ||||||
|     [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } |  | ||||||
|     [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } |  | ||||||
|     # args are valid |  | ||||||
|     if [[ -t 0 ]]; then |  | ||||||
|         echo -n "$3" | \ |  | ||||||
|          dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null |  | ||||||
|     else |  | ||||||
|         dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null |  | ||||||
|     fi |  | ||||||
| } |  | ||||||
|  |  | ||||||
| writecharDec () { |  | ||||||
| # write corresponding character of single-byte decimal value into file |  | ||||||
| # arg1: filename |  | ||||||
| # arg2: offset (# of bytes to skip before writing) |  | ||||||
| # arg3: decimal number from 0-255 |  | ||||||
| # exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2, |  | ||||||
| #       13=missing arg3, 22=invalid arg2, 23=invalid arg3 |  | ||||||
| #  out: nothing |  | ||||||
|     [[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13 |  | ||||||
|     [[ $4 ]] && return 8 |  | ||||||
|     [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ |  | ||||||
|      && ( $2 -ge 0 ) ]] || return 22 |  | ||||||
|     [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \ |  | ||||||
|      && ( $3 -ge 0 ) && ( $3 -lt 255 ) ]] || return 23 |  | ||||||
|     # args are valid |  | ||||||
|     echo -n -e "\x$(printf %02X "$3")" | \ |  | ||||||
|      dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null |  | ||||||
| } |  | ||||||
|  |  | ||||||
| writecharHex () { |  | ||||||
| # write corresponding character of single-byte hex value into file |  | ||||||
| # arg1: filename |  | ||||||
| # arg2: offset (# of bytes to skip before writing) |  | ||||||
| # arg3: two-digit hexadecimal number from 00-FF |  | ||||||
| #  out: nothing |  | ||||||
| # exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2, |  | ||||||
| #       13=missing arg3, 22=invalid arg2, 23=invalid arg3 |  | ||||||
|     [[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13 |  | ||||||
|     [[ $4 ]] && return 8 |  | ||||||
|     [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \ |  | ||||||
|      && ( $2 -ge 0 ) ]] || return 22 |  | ||||||
|     [[ $(printf %02X "0x$3" 2> /dev/null) == \ |  | ||||||
|      $(echo -n "$3" | tr [a-z] [A-Z]) ]] || return 23 |  | ||||||
|     # args are valid |  | ||||||
|     echo -n -e "\x$3" | \ |  | ||||||
|      dd of="$1" bs=1 seek=$2 conv=notrunc 2> /dev/null |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # --- afptype is below this line |  | ||||||
|  |  | ||||||
| isHexByte () { |  | ||||||
|     [[ $(printf %02X "0x$1" 2> /dev/null) == \ |  | ||||||
|      $(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 1 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| # support 00 and 0A as filetype chars? |  | ||||||
|  |  | ||||||
| debug=1 |  | ||||||
| ptypes="04:TXT 06:BIN B3:S16 E0:SHK F9:P16 FA:INT FC:BAS FF:SYS" |  | ||||||
|  |  | ||||||
| quit () { |  | ||||||
|     if [[ $2 && $debug ]]; then |  | ||||||
|         echo "$1" "$2" |  | ||||||
|     else |  | ||||||
|         echo -e "Error: $1" |  | ||||||
|     fi |  | ||||||
|     exit_usage |  | ||||||
| } |  | ||||||
|  |  | ||||||
| exit_usage () { |  | ||||||
|     echo "Usage:" |  | ||||||
|     echo |  | ||||||
|     echo "show types: afptype filename" |  | ||||||
|     echo "set Mac OS: afptype [-t 'type'] [-c 'creator'] [-q] filename" |  | ||||||
|     echo "set ProDOS: afptype [-p type] [-a auxtype] [-q] filename" |  | ||||||
|     echo "Mac OS type or creator must be four characters; use \x plus" |  | ||||||
|     echo "  two hex digits for untypeables (note: use '\xZZ' for 00)." |  | ||||||
|     echo "ProDOS type should be two hex digits, and auxtype should be four;" |  | ||||||
|     echo "  type can alternatively be BAS, BIN, INT, P16, S16, SHK, SYS, TXT." |  | ||||||
|     echo "-q skips recheck of file (show types) after setting"  |  | ||||||
|     echo |  | ||||||
|     exit 1 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| lookupPdosType () { |  | ||||||
| # looks up ProDOS hex type from code in list 'ptypes' |  | ||||||
| # arg: three-character code |  | ||||||
| # out: two-digit hex value |  | ||||||
| #exit: 0=type found, 1=error, 2=type not found |  | ||||||
|     ptypes="04:TXT 06:BIN B3:S16 E0:SHK F9:P16 FA:INT FC:BAS FF:SYS" |  | ||||||
|     [[ $1 ]] || quit "lookupPdosType:" "no argument supplied ($1)" |  | ||||||
|     [[ ${#1} -eq 3 ]] || return 1 |  | ||||||
|     arg=$(echo -n "$1" | tr [a-z] [A-Z]) |  | ||||||
|     for ptype in $ptypes; do |  | ||||||
|     if [[ ${ptype:3:3} == $arg ]] |  | ||||||
|         then |  | ||||||
|             echo -n "${ptype:0:2}" |  | ||||||
|             return 0 |  | ||||||
|         fi |  | ||||||
|     done |  | ||||||
|     echo "$1" |  | ||||||
|     return 1 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| verifyTC () { |  | ||||||
|     [[ $1 ]] || return 1 |  | ||||||
|     tcX="$(echo -e -n "$1"X)" |  | ||||||
|     [[ ${#tcX} -eq 5 ]] || return 1 |  | ||||||
|     echo "$tcX" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| while [[ $1 && ( "${1:0:1}" == '-' ) ]]; do |  | ||||||
|     if [[ $1 == "-p" ]]; then |  | ||||||
|         [[ $p ]] && exit_usage |  | ||||||
|         shift |  | ||||||
|         p="$1" |  | ||||||
|         shift |  | ||||||
|         continue |  | ||||||
|     elif [[ $1 == "-a" ]]; then |  | ||||||
|         [[ $a ]] && exit_usage |  | ||||||
|         shift |  | ||||||
|         a="$1" |  | ||||||
|         shift |  | ||||||
|         continue |  | ||||||
|     elif [[ $1 == "-t" ]]; then |  | ||||||
|         [[ $t ]] && exit_usage |  | ||||||
|         shift |  | ||||||
|         t="$1" |  | ||||||
|         shift |  | ||||||
|         continue |  | ||||||
|     elif [[ $1 == "-c" ]]; then |  | ||||||
|         [[ $c ]] && exit_usage |  | ||||||
|         shift |  | ||||||
|         c="$1" |  | ||||||
|         shift |  | ||||||
|         continue |  | ||||||
|     elif [[ $1 == "-q" ]]; then |  | ||||||
|         [[ $q ]] && exit_usage |  | ||||||
|         q=1 |  | ||||||
|         shift |  | ||||||
|         continue |  | ||||||
|     else |  | ||||||
|         exit_usage |  | ||||||
|         break    |  | ||||||
|     fi |  | ||||||
| done |  | ||||||
|  |  | ||||||
| if [[ ( ( $p || $a ) && ( $t || $c ) ) || ( -z $1 ) ]]; then |  | ||||||
|     exit_usage |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| #filename="$1" |  | ||||||
| #shift |  | ||||||
|  |  | ||||||
| for filename in $@; do |  | ||||||
|  |  | ||||||
|     [[ ${#@} -gt 1 ]] && linestart="($filename) " |  | ||||||
|  |  | ||||||
|     if [[ ! -f $filename ]]; then |  | ||||||
|         echo "${linestart}Not found." |  | ||||||
|         continue |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     adname="$(dirname "$filename")/.AppleDouble/$(basename "$filename")" |  | ||||||
|     [[ -f $adname ]] && filename=$adname |  | ||||||
|     ADversion=$(readcharDec "$filename" 5) |  | ||||||
|     if [[ ( ( $ADversion -ne 1 ) && ( $ADversion -ne 2 ) ) \ |  | ||||||
|     || ( "$(readchars "$filename" 1 3)" != "$(echo -e -n "\x05\x16\x07")" ) \ |  | ||||||
|     || ( $(readcharDec "$filename" 0) -ne 0 ) \ |  | ||||||
|     || ( $(readcharDec "$filename" 4) -ne 0 ) \ |  | ||||||
|     || ( $(readcharDec "$filename" 6) -ne 0 ) \ |  | ||||||
|     || ( $(readcharDec "$filename" 7) -ne 0 ) ]]; then |  | ||||||
|         echo "${linestart}Not an AppleDouble file." |  | ||||||
|         continue |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     entrycount=`readcharDec "$filename" 25` |  | ||||||
|      |  | ||||||
|     entry=1 |  | ||||||
|     offset=29 |  | ||||||
|  |  | ||||||
|     while [[ $(readcharDec "$filename" $offset) -ne 9 ]]; do |  | ||||||
|         (( entry = entry + 1 )) |  | ||||||
|         if (( entry > entrycount )); then |  | ||||||
|             echo "${linestart}Finder Info entry not found in AppleDouble file." |  | ||||||
|             break |  | ||||||
|         fi |  | ||||||
|         (( offset = (entry * 12 + 29) - 12 )) |  | ||||||
|     done |  | ||||||
|     (( entry > entrycount )) && continue |  | ||||||
|      |  | ||||||
|     (( offset = offset + 3 )) |  | ||||||
|     (( tposHi = $(readcharDec "$filename" $offset) * 256 )) |  | ||||||
|     (( offset = offset + 1 )) |  | ||||||
|     (( tpos = $(readcharDec "$filename" $offset) + tposHi )) |  | ||||||
|     (( cpos = tpos + 4 )) |  | ||||||
|     (( ppos = tpos + 1 )) |  | ||||||
|     (( apos = tpos + 2 )) |  | ||||||
|      |  | ||||||
|     if [[ $p || $a || $t || $c ]]; then # set |  | ||||||
|         if [[ $p || $a ]]; then |  | ||||||
|             if [[ $p ]]; then |  | ||||||
|                 [[ ${#p} -eq 3 ]] && { p=$(lookupPdosType $p) || quit "Invalid ProDOS type name ($p)."; } |  | ||||||
|                 isHexByte "$p" || quit "Invalid ProDOS file type ($p)." |  | ||||||
|                 writecharHex "$filename" $ppos "$p" |  | ||||||
|             fi |  | ||||||
|             if [[ $a ]]; then |  | ||||||
|                 isHexByte "${a:0:2}" && isHexByte "${a:2:2}" || quit "Invalid ProDOS aux type ($a)." |  | ||||||
|                 writecharHex "$filename" $apos "${a:0:2}" |  | ||||||
|                 (( apos=apos+1 )) |  | ||||||
|                 writecharHex "$filename" $apos "${a:2:2}" |  | ||||||
|             fi |  | ||||||
|             writechars "$filename" $tpos "p" |  | ||||||
|             writechars "$filename" $cpos "pdos" |  | ||||||
|         elif [[ $t || $c ]]; then |  | ||||||
|             if [[ $t ]]; then |  | ||||||
|                 type=$(verifyTC "$t") || quit "$(echo -n "Invalid Mac file type ($t)."; [[ $t == *x* ]] && echo -n " Try quotes."; echo)" |  | ||||||
|                 writechars "$filename" $tpos "${type:0:4}" |  | ||||||
|             fi |  | ||||||
|             if [[ $c ]]; then |  | ||||||
|                 creator=$(verifyTC "$c") || quit "$(echo -n "Invalid Mac file creator ($c)."; [[ $c == *x* ]] && echo -n " Try quotes."; echo)" |  | ||||||
|                 writechars "$filename" $cpos "${creator:0:4}" |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|         [[ $q ]] || { echo -n "${linestart}File changed: "; "$0" "$filename"; } |  | ||||||
|  |  | ||||||
|     else # show |  | ||||||
|         [[ $q ]] && quit "Can only use -q when changing type." |  | ||||||
|  |  | ||||||
|         type="$(readchars "$filename" $tpos 4)" |  | ||||||
|         creator="$(readchars "$filename" $cpos 4)" |  | ||||||
|          |  | ||||||
|         echo -n "$linestart" |  | ||||||
|      |  | ||||||
|         if [[ $creator != "pdos" || ( ( $type != "TEXT" ) \ |  | ||||||
|         && ( $type != "PSYS" ) && ( ${type:0:1} != "p" ) ) ]]; then |  | ||||||
|             if [[ $creator || $type ]]; then |  | ||||||
|                 echo "Mac file.   Type:$type   Creator:$creator" |  | ||||||
|             else |  | ||||||
|                 echo "This file has no Mac or ProDOS file type information." |  | ||||||
|             fi |  | ||||||
|             continue |  | ||||||
|         fi |  | ||||||
|          |  | ||||||
|         if [[ $type == "TEXT" ]]; then |  | ||||||
|             pdosType="\$04 [TXT]" |  | ||||||
|             pdosAuxType='$0000' |  | ||||||
|         elif [[ $type == "PSYS" ]]; then |  | ||||||
|             pdosType="\$FF [SYS]" |  | ||||||
|             pdosAuxType='$0000' |  | ||||||
|         else |  | ||||||
|             (( tpos=tpos+1 )) |  | ||||||
|             pdosType=$(readcharHex "$filename" $tpos) |  | ||||||
|             for ptype in $ptypes; do |  | ||||||
|                 if [[ "${ptype:0:2}" == "$pdosType" ]]; then |  | ||||||
|                     pdosType="$pdosType [${ptype:3:3}]" |  | ||||||
|                     break |  | ||||||
|                 fi |  | ||||||
|             done |  | ||||||
|          |  | ||||||
|             (( tpos=tpos+1 )) |  | ||||||
|             auxTypeHi=$(readcharHex "$filename" $tpos) |  | ||||||
|             (( tpos=tpos+1 )) |  | ||||||
|             auxTypeLo=$(readcharHex "$filename" $tpos) |  | ||||||
|             pdosAuxType=$auxTypeHi$auxTypeLo |  | ||||||
|         fi |  | ||||||
|          |  | ||||||
|         echo "ProDOS file.  Type:\$$pdosType   AuxType:\$$pdosAuxType" |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
| done |  | ||||||
|  |  | ||||||
| # 7-19-11 |  | ||||||
| # quick ProDOS testing/fixing on Linux, needs more |  | ||||||
| # Mac Type testing not done yet, nor testing on a Mac |  | ||||||
|  |  | ||||||
| # test on lunix |  | ||||||
| # test inside and outside of AD directory, and from other dirs (both cases) |  | ||||||
| # finish conversion writebyte/readchar library |  | ||||||
| # consider return 2 for missing parameters for subroutines |  | ||||||
| @@ -1,882 +0,0 @@ | |||||||
| #!/usr/bin/env python |  | ||||||
| """cppo: Copy or catalog one or all files from a ProDOS raw disk image. |  | ||||||
|  |  | ||||||
| copy all files: |  | ||||||
|     cppo [-ad|-e] imagefile target_directory |  | ||||||
| copy one file: |  | ||||||
|     cppo [-ad|-e] imagefile /FULL/PRODOS/FILE/PATH target_path |  | ||||||
| catalog image: |  | ||||||
|     cppo -cat imagefile |  | ||||||
|  |  | ||||||
| -ad : Create AppleDouble header files and preserve resource forks. |  | ||||||
| -e  : Append ProDOS type and auxtype to filenames, and copy resource |  | ||||||
|       forks, for adding to ShrinkIt archives with Nulib2 |  | ||||||
|       using its -e option. |  | ||||||
|  |  | ||||||
| Wildcard matching/globbing (*) is not supported. |  | ||||||
| No verification or validation of the disk image is performed. |  | ||||||
|  |  | ||||||
| (Compatible with Python 2.6 and later, including 3.x.) |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| # cppo by Ivan X, ivan@ivanx.com, ivanx.com/appleii |  | ||||||
|  |  | ||||||
| # If anyone's looking at this, and feels it's not sufficiently Pythonic, |  | ||||||
| # I know that. It's pretty much a line-for-line conversion of the original |  | ||||||
| # Bash script. I did start a beautiful from-the-ground-up object-oriented |  | ||||||
| # version, then realized it would be faster to translate it ugly and quick. |  | ||||||
|  |  | ||||||
| # imports for python 3 code compatibility |  | ||||||
| from __future__ import print_function |  | ||||||
| from __future__ import unicode_literals |  | ||||||
| from __future__ import absolute_import |  | ||||||
| from __future__ import division |  | ||||||
|  |  | ||||||
| import sys |  | ||||||
| import os |  | ||||||
| import time |  | ||||||
| import datetime |  | ||||||
|  |  | ||||||
| # Intentially fails on pre-2.6 so user can see what's wrong |  | ||||||
| b'ERROR: cppo requires Python 2.6 or later, including 3.x.' |  | ||||||
|  |  | ||||||
| class Globals(object): |  | ||||||
|     pass |  | ||||||
|  |  | ||||||
| g = Globals() |  | ||||||
|  |  | ||||||
| g.imageData = b'' |  | ||||||
| g.outFileData = bytearray(b'') |  | ||||||
| g.adFileData = bytearray(b'') |  | ||||||
| g.exFileData = bytearray(b'') |  | ||||||
|  |  | ||||||
| g.activeDirBlock = None |  | ||||||
| g.activeFileName = None |  | ||||||
| g.activeFileSize = None |  | ||||||
| g.activeFileBytesCopied = 0 |  | ||||||
| g.resourceFork = 0 |  | ||||||
|  |  | ||||||
| g.PDOSPATH = [] |  | ||||||
| g.PDOSPATH_INDEX = 0 |  | ||||||
| g.PDOSPATH_SEGMENT = None |  | ||||||
| g.DIRPATH = "" |  | ||||||
|  |  | ||||||
| g.targetName = None |  | ||||||
| g.targetDir = "" |  | ||||||
| g.ADdir = None |  | ||||||
| g.imageFile = None |  | ||||||
|  |  | ||||||
| g.AD = 0 |  | ||||||
| g.EX = 0 |  | ||||||
| g.DIR = 0 |  | ||||||
| g.silent = 0 |  | ||||||
|  |  | ||||||
| # functions |  | ||||||
|  |  | ||||||
| def pdosDateToUnixDate(arg1): |  | ||||||
|     # input: ProDOS date/time bit sequence string in format: |  | ||||||
|     #   "yyyyyyymmmmddddd000hhhhh00mmmmmm" (ustr) |  | ||||||
|     # output: seconds since Unix epoch (1-Jan-1970), |  | ||||||
|     #         or current date/time if no ProDOS date |  | ||||||
|     year = (binToDec(slyce(arg1,0,7)) + 1900) |  | ||||||
|     if (year < 1940): year += 100 |  | ||||||
|     month = binToDec(slyce(arg1,7,4)) |  | ||||||
|     day = binToDec(slyce(arg1,11,5)) |  | ||||||
|     hour = binToDec(slyce(arg1,19,5)) |  | ||||||
|     minute = binToDec(slyce(arg1,26,6)) |  | ||||||
|     # print(year, month, day, hour, minute) |  | ||||||
|     td = (datetime.datetime(year, month, day, hour, minute) - |  | ||||||
|            datetime.datetime(1970,1,1)) |  | ||||||
|     unixDate_naive = (td.days*24*60*60 + td.seconds) |  | ||||||
|     td2 = (datetime.datetime.fromtimestamp(unixDate_naive) - |  | ||||||
|                   datetime.datetime.utcfromtimestamp(unixDate_naive)) |  | ||||||
|     utcoffset = (td2.days*24*60*60 + td2.seconds) |  | ||||||
|     # print(unixDate_naive - utcoffset) |  | ||||||
|     return (unixDate_naive - utcoffset) # local time zone with DST |  | ||||||
|  |  | ||||||
| def unixDateToADDate(arg1): |  | ||||||
|     # input: seconds since Unix epoch (1-Jan-1970 00:00:00 GMT) |  | ||||||
|     # output: seconds since Netatalk epoch (1-Jan-2000 00:00:00 GMT), |  | ||||||
|     #         in hex-ustr (big endian) |  | ||||||
|     adDate = (arg1 - 946684800) |  | ||||||
|     if (adDate < 0 ): |  | ||||||
|         adDate += 4294967296 # to get negative hex number |  | ||||||
|     adDateHex = to_hex(adDate).zfill(8).upper() |  | ||||||
|     # print(arg1, adDate, adDateHex) |  | ||||||
|     return adDateHex |  | ||||||
|  |  | ||||||
| # cppo support routines: |  | ||||||
| # arg1: directory block |  | ||||||
| # arg2: file index (if applicable) |  | ||||||
| # arg3: directory chunk # (if applicable) |  | ||||||
|  |  | ||||||
| #most of these not tested yet in Python |  | ||||||
| # returns byte position in disk image file |  | ||||||
| def getStartPos(arg1, arg2): |  | ||||||
|     return ( (arg1 * 512) + |  | ||||||
|              (39 * ((arg2 + (arg2 > 11)) % 13)) + |  | ||||||
|              (4 if (arg2 > 11) else 43) ) |  | ||||||
|  |  | ||||||
| def getStorageType(arg1, arg2): |  | ||||||
|     start = getStartPos(arg1, arg2) |  | ||||||
|     firstByte = readcharDec(g.imageData, start) |  | ||||||
|     return (firstByte//16) |  | ||||||
|  |  | ||||||
| def getFileName(arg1, arg2): |  | ||||||
|     start = getStartPos(arg1, arg2) |  | ||||||
|     firstByte = readcharDec(g.imageData, start) |  | ||||||
|     entryType = (firstByte//16) |  | ||||||
|     nameLength = (firstByte - entryType*16) |  | ||||||
|     return readchars(g.imageData, start+1, nameLength) |  | ||||||
|  |  | ||||||
| def getFileType(arg1, arg2): |  | ||||||
|     start = getStartPos(arg1, arg2) |  | ||||||
|     return readcharHex(g.imageData, start+16) |  | ||||||
|      |  | ||||||
| def getKeyPointer(arg1, arg2): |  | ||||||
|     start = getStartPos(arg1, arg2) |  | ||||||
|     return (readcharDec(g.imageData, start+17) + |  | ||||||
|             readcharDec(g.imageData, start+18)*256) |  | ||||||
|  |  | ||||||
| def getFileLength(arg1, arg2): |  | ||||||
|     start = getStartPos(arg1, arg2) |  | ||||||
|     return (readcharDec(g.imageData, start+21) + |  | ||||||
|             readcharDec(g.imageData, start+22)*256 + |  | ||||||
|             readcharDec(g.imageData, start+23)*65536) |  | ||||||
|  |  | ||||||
| def getAuxType(arg1, arg2): |  | ||||||
|     start = getStartPos(arg1, arg2) |  | ||||||
|     return (readcharHex(g.imageData, start+32) + |  | ||||||
|             readcharHex(g.imageData, start+31)) |  | ||||||
|  |  | ||||||
| def getCreationDate(arg1, arg2): |  | ||||||
|     #outputs prodos creation date/time as Unix time |  | ||||||
|     #  (seconds since Jan 1 1970 GMT) |  | ||||||
|     #or None if there is none |  | ||||||
|     start = getStartPos(arg1, arg2) |  | ||||||
|     pdosDate = (hexToBin(readcharHex(g.imageData, start+25)) + |  | ||||||
|                 hexToBin(readcharHex(g.imageData, start+24)) + |  | ||||||
|                 hexToBin(readcharHex(g.imageData, start+27)) + |  | ||||||
|                 hexToBin(readcharHex(g.imageData, start+26))) |  | ||||||
|     try: |  | ||||||
|         rVal = pdosDateToUnixDate(pdosDate) |  | ||||||
|     except Exception: |  | ||||||
|         rVal = None |  | ||||||
|     return rVal |  | ||||||
|  |  | ||||||
| def getModifiedDate(arg1, arg2): |  | ||||||
|     #outputs prodos modified date/time as Unix time |  | ||||||
|     #  (seconds since Jan 1 1970 GMT) |  | ||||||
|     #or None if there is none |  | ||||||
|     start = getStartPos(arg1, arg2) |  | ||||||
|     pdosDate = (hexToBin(readcharHex(g.imageData, start+34)) + |  | ||||||
|                 hexToBin(readcharHex(g.imageData, start+33)) + |  | ||||||
|                 hexToBin(readcharHex(g.imageData, start+36)) + |  | ||||||
|                 hexToBin(readcharHex(g.imageData, start+35))) |  | ||||||
|     try: |  | ||||||
|         rVal = pdosDateToUnixDate(pdosDate) |  | ||||||
|     except Exception: |  | ||||||
|         rVal = None |  | ||||||
|     return rVal |  | ||||||
|  |  | ||||||
| def getVolumeName(): |  | ||||||
|     return getWorkingDirName(2) |  | ||||||
|  |  | ||||||
| def getWorkingDirName(arg1): |  | ||||||
|     start = ( arg1 * 512 ) |  | ||||||
|     firstByte = readcharDec(g.imageData, start+4) |  | ||||||
|     entryType = (firstByte//16) |  | ||||||
|     nameLength = (firstByte - entryType*16) |  | ||||||
|     return readchars(g.imageData, start+5, nameLength) |  | ||||||
|  |  | ||||||
| def getDirEntryCount(arg1): |  | ||||||
|     start = ( arg1 * 512 ) |  | ||||||
|     return (readcharDec(g.imageData, start+37) + |  | ||||||
|             readcharDec(g.imageData, start+38)*256) |  | ||||||
|  |  | ||||||
| def getDirNextChunkPointer(arg1): |  | ||||||
|     start = ( arg1 * 512 ) |  | ||||||
|     return (readcharDec(g.imageData, start+2) + |  | ||||||
|             readcharDec(g.imageData, start+3)*256) |  | ||||||
|  |  | ||||||
| # -- script begins in earnest here |  | ||||||
|  |  | ||||||
| def copyFile(arg1, arg2): |  | ||||||
|     g.outFileData = bytearray(b'') |  | ||||||
|     g.exFileData = bytearray(b'') |  | ||||||
|     g.activeFileBytesCopied = 0 |  | ||||||
|     storageType = getStorageType(arg1, arg2) |  | ||||||
|     keyPointer = getKeyPointer(arg1, arg2) |  | ||||||
|     fileLen = getFileLength(arg1, arg2) |  | ||||||
|     if (storageType == 1): #seedling |  | ||||||
|         copyBlock(keyPointer, fileLen) |  | ||||||
|     elif (storageType == 2): #sapling |  | ||||||
|         processIndexBlock(keyPointer) |  | ||||||
|     elif (storageType == 3): #tree |  | ||||||
|         processMasterIndexBlock(keyPointer) |  | ||||||
|     elif (storageType == 5): #extended (forked) |  | ||||||
|         processForkedFile(keyPointer) |  | ||||||
|  |  | ||||||
| def copyBlock(arg1, arg2): |  | ||||||
|     #arg1: block to copy |  | ||||||
|     #arg2: bytes to write (should be 512, |  | ||||||
|     #      unless final block with less than 512 bytes) |  | ||||||
|     #print(arg1 + " " + arg2 + " " + g.activeFileBytesCopied) |  | ||||||
|     if (arg1 == 0): |  | ||||||
|         outBytes = (b'\x00' * arg2) |  | ||||||
|     else: |  | ||||||
|         outBytes = slyce(g.imageData, arg1*512, arg2) |  | ||||||
|     if (g.resourceFork > 0): |  | ||||||
|         if g.AD: |  | ||||||
|             g.adFileData[g.activeFileBytesCopied+741: |  | ||||||
|                         (g.activeFileBytesCopied+741 + arg2)] = outBytes |  | ||||||
|         if g.EX: |  | ||||||
|             g.exFileData[g.activeFileBytesCopied: |  | ||||||
|                         (g.activeFileBytesCopied + arg2)] = outBytes |  | ||||||
|     else: |  | ||||||
|         g.outFileData[g.activeFileBytesCopied: |  | ||||||
|                      (g.activeFileBytesCopied + arg2)] = outBytes |  | ||||||
|     g.activeFileBytesCopied += arg2 |  | ||||||
|  |  | ||||||
| def processDir(arg1, arg2=None, arg3=None, arg4=None, arg5=None): |  | ||||||
|     # arg1: dirBlock |  | ||||||
|     # arg2/3/4/5: for non-key chunks: entryCount, entry#, |  | ||||||
|     #   workingDirName, processedEntryCount |  | ||||||
|  |  | ||||||
|     entryCount = None |  | ||||||
|     e = None |  | ||||||
|     pe = None |  | ||||||
|     workingDirName = None |  | ||||||
|  |  | ||||||
|     if arg2: |  | ||||||
|         entryCount = arg2 |  | ||||||
|         e = arg3 |  | ||||||
|         workingDirName = arg4 |  | ||||||
|         pe = arg5 |  | ||||||
|     else: |  | ||||||
|         e = 0 |  | ||||||
|         pe = 0 |  | ||||||
|         entryCount = getDirEntryCount(arg1) |  | ||||||
|         workingDirName = getWorkingDirName(arg1).decode("L1") |  | ||||||
|         g.DIRPATH = (g.DIRPATH + "/" + workingDirName) |  | ||||||
|         if g.PDOSPATH_INDEX: |  | ||||||
|             if (g.PDOSPATH_INDEX == 1): |  | ||||||
|                 if (("/" + g.PDOSPATH_SEGMENT) != g.DIRPATH): |  | ||||||
|                     print("ProDOS volume name does not match disk image.") |  | ||||||
|                     sys.exit(2) |  | ||||||
|                 else: |  | ||||||
|                     g.PDOSPATH_INDEX += 1 |  | ||||||
|                     g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] |  | ||||||
|         else: |  | ||||||
|             print(g.DIRPATH) |  | ||||||
|     while (pe < entryCount): |  | ||||||
|         if (getStorageType(arg1, e) > 0): |  | ||||||
|             processEntry(arg1, e) |  | ||||||
|             pe += 1 |  | ||||||
|         e += 1 |  | ||||||
|         if not ((e + ( e>11 ) ) % 13): |  | ||||||
|             processDir(getDirNextChunkPointer(arg1), |  | ||||||
|                        entryCount, |  | ||||||
|                        e, |  | ||||||
|                        workingDirName, |  | ||||||
|                        pe) |  | ||||||
|             break |  | ||||||
|  |  | ||||||
| def processEntry(arg1, arg2): |  | ||||||
|     ''' |  | ||||||
|     print(getFileName(arg1, arg2), getStorageType(arg1, arg2), |  | ||||||
|           getFileType(arg1, arg2), getKeyPointer(arg1, arg2), |  | ||||||
|           getFileLength(arg1, arg2), getAuxType(arg1, arg2), |  | ||||||
|           getCreationDate(arg1, arg2), getModifiedDate(arg1, arg2)) |  | ||||||
|     ''' |  | ||||||
|     g.activeFileName = getFileName(arg1 ,arg2).decode("L1") |  | ||||||
|     g.activeFileSize = getFileLength(arg1, arg2) |  | ||||||
|  |  | ||||||
|     if ((not g.PDOSPATH_INDEX) or (g.activeFileName == g.PDOSPATH_SEGMENT)): |  | ||||||
|  |  | ||||||
|         if (getStorageType(arg1, arg2) == 13): # if ProDOS directory |  | ||||||
|             if not g.PDOSPATH_INDEX: |  | ||||||
|                 g.targetDir = (g.targetDir + "/" + g.activeFileName) |  | ||||||
|             g.ADdir = (g.targetDir + "/.AppleDouble") |  | ||||||
|             if not (g.DIR or os.path.isdir(g.targetDir)): |  | ||||||
|                 makedirs(g.targetDir) |  | ||||||
|             if not (g.DIR or (not g.AD) or os.path.isdir(g.ADdir)): |  | ||||||
|                 makedirs(g.ADdir) |  | ||||||
|             if g.PDOSPATH_SEGMENT: |  | ||||||
|                 g.PDOSPATH_INDEX += 1 |  | ||||||
|                 g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] |  | ||||||
|             processDir(getKeyPointer(arg1, arg2)) |  | ||||||
|             g.DIRPATH = g.DIRPATH.rsplit("/", 1)[0] |  | ||||||
|             if not g.PDOSPATH_INDEX: |  | ||||||
|                 g.targetDir = g.targetDir.rsplit("/", 1)[0] |  | ||||||
|             g.ADdir = (g.targetDir + "/.AppleDouble") |  | ||||||
|         else: # if ProDOS file |  | ||||||
|             if not g.PDOSPATH_INDEX: |  | ||||||
|                 print("   " + g.activeFileName) |  | ||||||
|             if g.DIR: |  | ||||||
|                 return |  | ||||||
|             if not g.targetName: |  | ||||||
|                 g.targetName = g.activeFileName |  | ||||||
|             if g.EX: |  | ||||||
|                 eTargetName = (g.targetName + "#" + |  | ||||||
|                                getFileType(arg1, arg2).lower() + |  | ||||||
|                                getAuxType(arg1, arg2).lower()) |  | ||||||
|             touch(g.targetDir + "/" + g.targetName) |  | ||||||
|             if g.AD: makeADfile() |  | ||||||
|             copyFile(arg1, arg2) |  | ||||||
|             saveFile((g.targetDir + "/" + g.targetName), g.outFileData) |  | ||||||
|             creationDate = getCreationDate(arg1, arg2) |  | ||||||
|             modifiedDate = getModifiedDate(arg1, arg2) |  | ||||||
|             if (creationDate is None and modifiedDate is not None): |  | ||||||
|                 creationDate = modifiedDate |  | ||||||
|             elif (creationDate is not None and modifiedDate is None): |  | ||||||
|                 modifiedDate = creationDate |  | ||||||
|             elif (creationDate is None and modifiedDate is None): |  | ||||||
|                 creationDate = (datetime.datetime.today() - |  | ||||||
|                                 datetime.datetime(1970,1,1)).days*24*60*60 |  | ||||||
|                 modifiedDate = creationDate |  | ||||||
|             if g.AD: # AppleDouble |  | ||||||
|                 # set dates |  | ||||||
|                 ADfilePath = (g.ADdir + "/" + g.targetName) |  | ||||||
|                 writecharsHex(g.adFileData, |  | ||||||
|                               637, |  | ||||||
|                               (unixDateToADDate(creationDate) + |  | ||||||
|                                unixDateToADDate(modifiedDate))) |  | ||||||
|                 writecharHex(g.adFileData, 645, "80") |  | ||||||
|                 writecharHex(g.adFileData, 649, "80") |  | ||||||
|                 #set type/creator |  | ||||||
|                 writechars(g.adFileData, 653, b'p') |  | ||||||
|                 writecharsHex(g.adFileData, |  | ||||||
|                               654, |  | ||||||
|                               (getFileType(arg1, arg2) + |  | ||||||
|                                getAuxType(arg1, arg2))) |  | ||||||
|                 writechars(g.adFileData, 657, b'pdos') |  | ||||||
|                 saveFile(ADfilePath, g.adFileData) |  | ||||||
|             touch((g.targetDir + "/" + g.targetName), modifiedDate) |  | ||||||
|             if g.EX: # extended name |  | ||||||
|                 os.rename((g.targetDir + "/" + g.targetName), |  | ||||||
|                           (g.targetDir + "/" + eTargetName)) |  | ||||||
|                 if (len(g.exFileData) > 0): |  | ||||||
|                     saveFile((g.targetDir + "/" + eTargetName + "r"), |  | ||||||
|                               g.exFileData) |  | ||||||
|                     touch((g.targetDir + "/" + eTargetName + "r"), |  | ||||||
|                            modifiedDate) |  | ||||||
|             if g.PDOSPATH_SEGMENT: |  | ||||||
|                 syncExit() |  | ||||||
|             g.targetName = None |  | ||||||
|      |  | ||||||
|     #else: |  | ||||||
|         #print(g.activeFileName + " doesn't match " + g.PDOSPATH_SEGMENT) |  | ||||||
|  |  | ||||||
| def processForkedFile(arg1): |  | ||||||
|     # finder info except type/creator |  | ||||||
|     fInfoA_entryType = readcharDec(g.imageData, 9) |  | ||||||
|     fInfoB_entryType = readcharDec(g.imageData, 27) |  | ||||||
|     if (fInfoA_entryType == 1): |  | ||||||
|         writechars(g.imageData, 661, readchars(g.imageData, 18, 8)) |  | ||||||
|     elif (fInfoA_entryType == 2): |  | ||||||
|         writechars(g.imageData, 669, readchars(g.imageData, 10, 16)) |  | ||||||
|     if (fInfoB_entryType == 1): |  | ||||||
|         writechars(g.imageData, 661, readchars(g.imageData, 36, 8)) |  | ||||||
|     elif (fInfoB_entryType == 2): |  | ||||||
|         writechars(g.imageData, 669, readchars(g.imageData, 28, 16)) |  | ||||||
|  |  | ||||||
|     for f in [0, 256]: |  | ||||||
|         g.resourceFork = f |  | ||||||
|         g.activeFileBytesCopied = 0 |  | ||||||
|         forkStart = (arg1 * 512) # start of Forked File key block |  | ||||||
|         # print("--" + forkStart) |  | ||||||
|         forkStorageType = readcharDec(g.imageData, forkStart+f+0) |  | ||||||
|         forkKeyPointer = (readcharDec(g.imageData, forkStart+f+1) + |  | ||||||
|                           readcharDec(g.imageData, forkStart+f+2)*256) |  | ||||||
|         forkFileLen = (readcharDec(g.imageData, forkStart+f+5) + |  | ||||||
|                        readcharDec(g.imageData, forkStart+f+6)*256 + |  | ||||||
|                        readcharDec(g.imageData, forkStart+f+7)*256*256) |  | ||||||
|         g.activeFileSize = forkFileLen |  | ||||||
|         if (g.resourceFork > 0): |  | ||||||
|             rsrcForkLenHex = (readcharHex(g.imageData, forkStart+f+7) + |  | ||||||
|                               readcharHex(g.imageData, forkStart+f+6) + |  | ||||||
|                               readcharHex(g.imageData, forkStart+f+5)) |  | ||||||
|             # print(">>>" + rsrcForkLenHex) |  | ||||||
|             print("    [resource fork]") |  | ||||||
|             if g.AD: |  | ||||||
|                 writecharsHex(g.adFileData, 35, rsrcForkLenHex) |  | ||||||
|         else: |  | ||||||
|             print("    [data fork]") |  | ||||||
|         if (forkStorageType == 1): #seedling |  | ||||||
|             copyBlock(forkKeyPointer, forkFileLen) |  | ||||||
|         elif (forkStorageType == 2): #sapling |  | ||||||
|             processIndexBlock(forkKeyPointer) |  | ||||||
|         elif (forkStorageType == 3): #tree |  | ||||||
|             processMasterIndexBlock(forkKeyPointer) |  | ||||||
|     # print() |  | ||||||
|     g.resourceFork = 0 |  | ||||||
|  |  | ||||||
| def processMasterIndexBlock(arg1): |  | ||||||
|     processIndexBlock(arg1, True) |  | ||||||
|  |  | ||||||
| def processIndexBlock(arg1, arg2=False): |  | ||||||
|     #arg1: indexBlock |  | ||||||
|     #arg2: if True, it's a Master Index Block |  | ||||||
|     pos = 0 |  | ||||||
|     bytesRemaining = g.activeFileSize |  | ||||||
|     while (g.activeFileBytesCopied < g.activeFileSize): |  | ||||||
|         targetBlock = (readcharDec(g.imageData, arg1*512+pos) + |  | ||||||
|                        readcharDec(g.imageData, arg1*512+(pos+256))*256) |  | ||||||
|         if arg2: |  | ||||||
|             processIndexBlock(targetBlock) |  | ||||||
|         else: |  | ||||||
|             bytesRemaining = (g.activeFileSize - g.activeFileBytesCopied) |  | ||||||
|             bs = (bytesRemaining if (bytesRemaining < 512) else 512) |  | ||||||
|             copyBlock(targetBlock, bs) |  | ||||||
|         pos += 1 |  | ||||||
|         if (pos > 255): |  | ||||||
|             break # go to next entry in Master Index Block (tree) |  | ||||||
|  |  | ||||||
| def makeADfile(): |  | ||||||
|     if not g.AD: return |  | ||||||
|     touch(g.ADdir + "/" + g.targetName) |  | ||||||
|     g.adFileData = bytearray(b'\x00' * 741) |  | ||||||
|     # ADv2 header |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("00"), "0005160700020000") |  | ||||||
|     # number of entries |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("18"), "000D") |  | ||||||
|     # Resource Fork |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("1A"), "00000002000002E500000000") |  | ||||||
|     # Real Name |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("26"), "00000003000000B600000000") |  | ||||||
|     # Comment |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("32"), "00000004000001B500000000") |  | ||||||
|     # Dates Info |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("3E"), "000000080000027D00000010") |  | ||||||
|     # Finder Info |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("4A"), "000000090000028D00000020") |  | ||||||
|     # ProDOS file info |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("56"), "0000000B000002C100000008") |  | ||||||
|     # AFP short name |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("62"), "0000000D000002B500000000") |  | ||||||
|     # AFP File Info |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("6E"), "0000000E000002B100000004") |  | ||||||
|     # AFP Directory ID |  | ||||||
|     writecharsHex(g.adFileData, hexToDec("7A"), "0000000F000002AD00000004") |  | ||||||
|     # dbd (second time) will create DEV, INO, SYN, SV~ |  | ||||||
|  |  | ||||||
| def syncExit(): |  | ||||||
|     if (not g.silent and g.AD and os.path.isdir("/usr/local/etc/netatalk")): |  | ||||||
|         print("File(s) have been copied to the target directory. " + |  | ||||||
|               "If the directory") |  | ||||||
|         print("is shared by Netatalk, please type 'afpsync' now.") |  | ||||||
|     # saveFile(g.imageFile, g.imageData) |  | ||||||
|     sys.exit(0) |  | ||||||
|  |  | ||||||
| def usage(): |  | ||||||
|     print(sys.modules[__name__].__doc__) |  | ||||||
|     sys.exit(1) |  | ||||||
|  |  | ||||||
| # --- ID bashbyter functions (adapted) |  | ||||||
|  |  | ||||||
| def decToHex(arg1): |  | ||||||
| # converts single-byte decimal value to hexadecimal equivalent |  | ||||||
| # arg: decimal value from 0-255 |  | ||||||
| # out: two-digit hex string from 00-FF |  | ||||||
| #exit: 21=invalid arg |  | ||||||
|     if (arg1<0 or arg1>255): sys.exit(21) |  | ||||||
|     return to_hex(arg1).upper() |  | ||||||
|  |  | ||||||
| def hexToDec(arg1): |  | ||||||
| # converts single-byte hexadecimal value to decimal equivalent |  | ||||||
| # arg: two-digit hex value from 00-FF |  | ||||||
| # out: decimal value |  | ||||||
| #exit: 21=invalid arg |  | ||||||
|     if (len(arg1) != 2): return 21 |  | ||||||
|     return to_dec(arg1) |  | ||||||
|  |  | ||||||
| def hexToBin(arg1): |  | ||||||
| # converts single-byte hexadecimal value to binary string |  | ||||||
| # arg: two-digit hex value from 00-FF |  | ||||||
| # out: binary string value |  | ||||||
| #exit: 21=invalid arg |  | ||||||
|     if (len(arg1) != 2): return 21 |  | ||||||
|     return to_bin(arg1).zfill(8) |  | ||||||
|  |  | ||||||
| def binToDec(arg1): |  | ||||||
| # converts single-byte binary string (8 bits) value to decimal |  | ||||||
| # warning: no error checking |  | ||||||
| # arg: binary string up to 8 bits |  | ||||||
| # out: decimal value |  | ||||||
|     return to_dec([arg1]) |  | ||||||
|      |  | ||||||
| def binToHex(arg1): |  | ||||||
| # converts single-byte binary string (8 bits) value to hex |  | ||||||
| # warning: no error checking |  | ||||||
| # arg: binary string up to 8 bits |  | ||||||
| # out: hex value |  | ||||||
|     return to_hex(arg1).upper() |  | ||||||
|  |  | ||||||
| def charToDec(arg1): |  | ||||||
| # converts single char (of type bytes) to corresponding decimal value |  | ||||||
| # arg: one char (of type bytes) |  | ||||||
| # out: decimal value from 0-255 |  | ||||||
| #exit: 21=invalid arg |  | ||||||
|     if (len(arg1) != 1): return 21 |  | ||||||
|     return to_dec(arg1) |  | ||||||
|  |  | ||||||
| def charToHex(arg1): |  | ||||||
| # converts single char (of type bytes) to corresponding hex value |  | ||||||
| # arg: one char (of type bytes) |  | ||||||
| # out: hexadecimal value from 00-FF |  | ||||||
| #exit: 21=invalid arg |  | ||||||
|     if (len(arg1) != 1): return 21 |  | ||||||
|     return to_hex(arg1).upper() |  | ||||||
|  |  | ||||||
| def decToChar(arg1): |  | ||||||
| # converts single-byte decimal value to equivalent char (of type bytes) |  | ||||||
| # arg: decimal number from 0-255 |  | ||||||
| # out: one character |  | ||||||
| #exit: 21=invalid arg |  | ||||||
|     if (arg1<0 or arg1>255): sys.exit(21) |  | ||||||
|     return to_bytes(arg1) |  | ||||||
|  |  | ||||||
| def hexToChar(arg1): |  | ||||||
| # converts single-byte hex value to corresponding char (of type bytes) |  | ||||||
| # arg: two-digit hexadecimal number from 00-FF |  | ||||||
| # out: one character |  | ||||||
| #exit: 21=invalid arg |  | ||||||
|     if (len(arg1) != 2): return 21 |  | ||||||
|     return to_bytes(arg1) |  | ||||||
|  |  | ||||||
| def readchars(arg1, arg2=0, arg3=0): |  | ||||||
| # read one or more characters from a bytes variable |  | ||||||
| # arg1: bytes or bytearray variable |  | ||||||
| # arg2: (optional) offset (# of bytes to skip before reading) |  | ||||||
| # arg3: (optional) # of chars to read (default is to end of bytes var) |  | ||||||
| #  out: sequence of characters (bytes or bytearray) |  | ||||||
| # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 |  | ||||||
|     if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): |  | ||||||
|         sys.exit(21) |  | ||||||
|     if (arg2<0): sys.exit(22) |  | ||||||
|     if (arg3<0): sys.exit(23) |  | ||||||
|     if (arg3 == 0): |  | ||||||
|         arg3 = len(arg1) |  | ||||||
|     return slyce(arg1, arg2, arg3) |  | ||||||
|  |  | ||||||
| def readcharDec(arg1, arg2=0): |  | ||||||
| # read one character from bytes var & convert to equivalent dec value |  | ||||||
| # arg1: bytes var |  | ||||||
| # arg2: (optional) offset (# of bytes to skip before reading) |  | ||||||
| #  out: decimal value from 0-255 |  | ||||||
| # exit: 21=invalid arg1, 22=invalid arg2 |  | ||||||
|     if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): |  | ||||||
|         sys.exit(21) |  | ||||||
|     if (arg2<0): sys.exit(22) |  | ||||||
|     return to_dec(slyce(arg1, arg2, 1)) |  | ||||||
|  |  | ||||||
| def readcharHex(arg1, arg2=0): |  | ||||||
| # read one character from bytes var & convert to corresponding hex value |  | ||||||
| # arg1: bytes var |  | ||||||
| # arg2: (optional) offset (# of bytes to skip before reading) |  | ||||||
| #  out: two-digit hex value from 00-FF |  | ||||||
| # exit: 21=invalid arg1, 22=invalid arg2 |  | ||||||
|     if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)): |  | ||||||
|         sys.exit(21) |  | ||||||
|     if (arg2<0): sys.exit(22) |  | ||||||
|     return to_hex(slyce(arg1, arg2, 1)) |  | ||||||
|  |  | ||||||
| def writechars(arg1, arg2, arg3): |  | ||||||
| # write one or more characters (bytes) to bytearray |  | ||||||
| # arg1: bytearray variable |  | ||||||
| # arg2: offset (# of bytes to skip before writing) |  | ||||||
| # arg3: sequence of bytes (or bytearray) |  | ||||||
| #  out: nothing |  | ||||||
| # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 |  | ||||||
|     if not isinstance(arg1, bytearray): sys.exit(21) |  | ||||||
|     if (arg2<0): sys.exit(22) |  | ||||||
|     if not (isinstance(arg3, bytes) or isinstance(arg3, bytearray)): |  | ||||||
|         sys.exit(23) |  | ||||||
|     arg1[arg2:arg2+len(arg3)] = arg3 |  | ||||||
|  |  | ||||||
| def writecharDec(arg1, arg2, arg3): |  | ||||||
| # write corresponding char of single-byte decimal value into bytearray |  | ||||||
| # arg1: bytearray |  | ||||||
| # arg2: offset (# of bytes to skip before writing) |  | ||||||
| # arg3: decimal number from 0-255 |  | ||||||
| # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 |  | ||||||
| #  out: nothing |  | ||||||
|     if not isinstance(arg1, bytearray): sys.exit(21) |  | ||||||
|     if (arg2<0): sys.exit(22) |  | ||||||
|     if not isnumber(arg3): sys.exit(23) |  | ||||||
|     arg1[arg2:arg2+1] = to_bytes(arg3) |  | ||||||
|  |  | ||||||
| def writecharHex(arg1, arg2, arg3): |  | ||||||
| # write corresponding character of single-byte hex value into bytearray |  | ||||||
| # arg1: bytearray |  | ||||||
| # arg2: offset (# of bytes to skip before writing) |  | ||||||
| # arg3: two-digit hexadecimal number from 00-FF |  | ||||||
| #  out: nothing |  | ||||||
| # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 |  | ||||||
|     if not isinstance(arg1, bytearray): sys.exit(21) |  | ||||||
|     if (arg2<0): sys.exit(22) |  | ||||||
|     if not isinstance(arg3, type("".encode().decode())): sys.exit(23) |  | ||||||
|     arg1[arg2:arg2+1] = to_bytes(arg3) |  | ||||||
|  |  | ||||||
| def writecharsHex(arg1, arg2, arg3): |  | ||||||
| # write corresponding characters of hex values into bytearray |  | ||||||
| # arg1: bytearray |  | ||||||
| # arg2: offset (# of bytes to skip before writing) |  | ||||||
| # arg3: string of two-digit hexadecimal numbers from 00-FF |  | ||||||
| #  out: nothing |  | ||||||
| # exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3 |  | ||||||
|     if not isinstance(arg1, bytearray): sys.exit(21) |  | ||||||
|     if (arg2<0): sys.exit(22) |  | ||||||
|     if not isinstance(arg3, type("".encode().decode())): sys.exit(23) |  | ||||||
|     arg1[arg2:arg2+len(to_bytes(arg3))] = to_bytes(arg3) |  | ||||||
|  |  | ||||||
| #---- IvanX general purpose functions ----# |  | ||||||
|  |  | ||||||
| def slyce(val, start_pos=0, length=1, reverse=False): |  | ||||||
|     """returns slice of object (but not a slice object) |  | ||||||
|     allows specifying length, and 3.x "bytes" consistency""" |  | ||||||
|     the_slyce = val[start_pos:start_pos+length] |  | ||||||
|     return (the_slyce[::-1] if reverse else the_slyce) |  | ||||||
|  |  | ||||||
| def to_hex(val): |  | ||||||
|     """convert bytes, decimal number, or [bin-ustr] to two-digit hex values |  | ||||||
|     unlike hex(), accepts bytes; has no leading 0x or trailing L""" |  | ||||||
|     from binascii import b2a_hex |  | ||||||
|     if isinstance(val, list): # [bin-ustr] |  | ||||||
|         val = int(val[0], 2) |  | ||||||
|     if isinstance(val, bytes): # bytes |  | ||||||
|         return b2a_hex(val).decode("L1") |  | ||||||
|     elif isnumber(val): |  | ||||||
|         # .encode().decode() always returns unicode in both P2 and P3 |  | ||||||
|         return (hex(val)[2:].split("L")[0]).encode("L1").decode("L1") |  | ||||||
|     else: |  | ||||||
|         raise Exception("to_hex() requires bytes, int/long, or [bin-ustr]") |  | ||||||
|  |  | ||||||
| def hex_slyce(val, start_pos=0, length=1, little_endian=False): |  | ||||||
|     """returns bytes slyce as hex-ustr""" |  | ||||||
|     return to_hex(slyce(val, start_pos, length, little_endian)) |  | ||||||
|  |  | ||||||
| def dec_slyce(val, start_pos=0, length=1, little_endian=False): |  | ||||||
|     """returns bytes slyce converted to decimal int/long""" |  | ||||||
|     return to_dec(hex_slyce(val, start_pos, length, little_endian)) |  | ||||||
|  |  | ||||||
| def bin_slyce(val, start_pos=0, length=1, little_endian=False): |  | ||||||
|     """returns bytes slyce converted to bin-ustr""" |  | ||||||
|     return to_bin(hex_slyce(val, start_pos, length, little_endian)) |  | ||||||
|  |  | ||||||
| def to_dec(val): |  | ||||||
|     """convert bytes, hex-ustr or [bin-ustr] to decimal int/long""" |  | ||||||
|     if isinstance(val, list): # [bin-ustr] |  | ||||||
|         return int(val[0], 2) |  | ||||||
|     elif isinstance(val, bytes): # bytes |  | ||||||
|         return int(to_hex(val), 16) |  | ||||||
|     elif isinstance(val, type("".encode().decode())): # hex-ustr |  | ||||||
|         return int(val, 16) |  | ||||||
|     else: |  | ||||||
|         raise Exception("to_dec() requires bytes, hex-ustr or [bin-ustr]") |  | ||||||
|  |  | ||||||
| def to_bin(val): |  | ||||||
|     """convert bytes, hex-ustr, or int/long to bin-ustr""" |  | ||||||
|     if isinstance(val, bytes): # bytes |  | ||||||
|         return (bin(to_dec(to_hex(val))))[2:].encode("L1").decode("L1") |  | ||||||
|     elif isinstance(val, type("".encode().decode())): # hex-ustr |  | ||||||
|         return (bin(int(val, 16)))[2:].encode("L1").decode("L1") |  | ||||||
|     elif isnumber(val): # int/long |  | ||||||
|         return (bin(val))[2:].encode("L1").decode("L1") |  | ||||||
|     else: |  | ||||||
|         raise Exception("to_bin() requires bytes, hex-ustr, or int/long") |  | ||||||
|  |  | ||||||
| def to_bytes(val): |  | ||||||
|     """converts hex-ustr, int/long, or [bin-ustr] to bytes""" |  | ||||||
|     from binascii import a2b_hex |  | ||||||
|     if isinstance(val, list): # [bin-ustr] |  | ||||||
|         val = to_hex(val[0]) |  | ||||||
|     if isnumber(val): # int/long |  | ||||||
|         val = to_hex(val) |  | ||||||
|     if isinstance(val, type("".encode().decode())): # hex-ustr |  | ||||||
|         return a2b_hex(bytes(val.encode("L1"))) # works on both P2 and P3 |  | ||||||
|     else: |  | ||||||
|         raise Exception( |  | ||||||
|           "to_bytes() requires hex-ustr, int/long, or [bin-ustr]") |  | ||||||
|      |  | ||||||
| def shift(items): |  | ||||||
|     """Shift list items to left, losing the first item. |  | ||||||
|      |  | ||||||
|     in : list |  | ||||||
|     out: list |  | ||||||
|     """ |  | ||||||
|     for i in range(0, (len(items)-1)): |  | ||||||
|         items[i] = items[i+1] |  | ||||||
|     del items[-1] |  | ||||||
|     return items |  | ||||||
|      |  | ||||||
| def s(string): |  | ||||||
|     """Perform local variable substution, e.g. 'total: {num} items'""" |  | ||||||
|     # http://stackoverflow.com/questions/2960772/ |  | ||||||
|     #        putting-a-variable-inside-a-string-python |  | ||||||
|     # http://stackoverflow.com/questions/6618795/ |  | ||||||
|     #        get-locals-from-calling-namespace-in-python |  | ||||||
|     import inspect |  | ||||||
|     frame = inspect.currentframe() |  | ||||||
|     try: |  | ||||||
|         rVal = string.format(**frame.f_back.f_locals) |  | ||||||
|     finally: |  | ||||||
|         del frame |  | ||||||
|     return rVal |  | ||||||
|  |  | ||||||
| def get_object_names(cls, include_subclasses=True): |  | ||||||
|     object_names = [] |  | ||||||
|     for (this_object_name, this_object_id) in list(globals().items()): |  | ||||||
|         if include_subclasses: |  | ||||||
|             if isinstance(this_object_id, cls): |  | ||||||
|                  object_names.append(this_object_name) |  | ||||||
|         else: |  | ||||||
|             if type(this_object_id) is cls: |  | ||||||
|                  object_names.append(this_object_name) |  | ||||||
|     return object_names |  | ||||||
|  |  | ||||||
| def touch(filePath, modTime=None): |  | ||||||
|     # http://stackoverflow.com/questions/1158076/implement-touch-using-python |  | ||||||
|     import os |  | ||||||
|     if (os.name == "nt"): |  | ||||||
|         if filePath[-1] == ".": filePath += "-" |  | ||||||
|         filePath = filePath.replace("./", ".-/") |  | ||||||
|     with open(filePath, "ab"): |  | ||||||
|         os.utime(filePath, (None if (modTime is None) else (modTime, modTime))) |  | ||||||
|  |  | ||||||
| def mkdir(dirPath): |  | ||||||
|     import os |  | ||||||
|     if (os.name == "nt"): |  | ||||||
|         if dirPath[-1] == ".": dirPath += "-" |  | ||||||
|         dirPath = dirPath.replace("./", ".-/") |  | ||||||
|     try: |  | ||||||
|         os.mkdir(dirPath) |  | ||||||
|     except FileExistsError: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
| def makedirs(dirPath): |  | ||||||
|     import os |  | ||||||
|     if (os.name == "nt"): |  | ||||||
|         if dirPath[-1] == ".": dirPath += "-" |  | ||||||
|         dirPath = dirPath.replace("./", ".-/") |  | ||||||
|     try: |  | ||||||
|         os.makedirs(dirPath) |  | ||||||
|     except FileExistsError: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
| def loadFile(filePath): |  | ||||||
|     import os |  | ||||||
|     if (os.name == "nt"): |  | ||||||
|         if filePath[-1] == ".": filePath += "-" |  | ||||||
|         filePath = filePath.replace("./", ".-/") |  | ||||||
|     with open(filePath, "rb") as imageHandle: |  | ||||||
|         return imageHandle.read() |  | ||||||
|  |  | ||||||
| def saveFile(filePath, fileData): |  | ||||||
|     import os |  | ||||||
|     if (os.name == "nt"): |  | ||||||
|         if filePath[-1] == ".": filePath += "-" |  | ||||||
|         filePath = filePath.replace("./", ".-/") |  | ||||||
|     with open(filePath, "wb") as imageHandle: |  | ||||||
|         imageHandle.write(fileData) |  | ||||||
|  |  | ||||||
| def isnumber(number): |  | ||||||
|     try: # make sure it's not a string |  | ||||||
|         len(number) |  | ||||||
|         return False |  | ||||||
|     except TypeError: |  | ||||||
|         pass |  | ||||||
|     try: |  | ||||||
|         int(number) |  | ||||||
|     except ValueError: |  | ||||||
|         return False |  | ||||||
|     return True |  | ||||||
|  |  | ||||||
| #---- end IvanX general purpose functions ----# |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # --- start |  | ||||||
|  |  | ||||||
| args = sys.argv |  | ||||||
| if (len(args) == 1): |  | ||||||
|     usage() |  | ||||||
|  |  | ||||||
| if (args[1] == "-s"): |  | ||||||
|     g.silent=1 |  | ||||||
|     args = args[1:] #shift |  | ||||||
|  |  | ||||||
| if (args[1] == "-ad"): |  | ||||||
|     g.AD = 1 |  | ||||||
|     args = args[1:] #shift |  | ||||||
|  |  | ||||||
| if (args[1] == "-e"): |  | ||||||
|     if g.AD: usage() |  | ||||||
|     g.EX = 1 |  | ||||||
|     args = args[1:] #shift |  | ||||||
|  |  | ||||||
| if (args[1] == "-cat"): |  | ||||||
|     g.DIR = 1 |  | ||||||
|     args = args[1:] |  | ||||||
|  |  | ||||||
| if not ((g.DIR and len(args) >= 2) or (len(args) >= 3)): |  | ||||||
|     usage() |  | ||||||
| if ((len(args) == 4) and |  | ||||||
|     (slyce(args[2],0,1) != "/") and |  | ||||||
|     (slyce(args[2],0,1) != ":")): |  | ||||||
|     usage() |  | ||||||
|  |  | ||||||
| g.imageFile = args[1] |  | ||||||
| if not os.path.isfile(g.imageFile): |  | ||||||
|     print("Source " + g.imageFile + " was not found.") |  | ||||||
|     sys.exit(2) |  | ||||||
| g.imageData = loadFile(g.imageFile) |  | ||||||
|  |  | ||||||
| if (len(args) == 4): |  | ||||||
|     g.PDOSPATH = args[2].upper() |  | ||||||
|     targetPath = args[3] |  | ||||||
|     if os.path.isdir(targetPath): |  | ||||||
|         g.targetDir = targetPath |  | ||||||
|     else: |  | ||||||
|         g.targetDir = targetPath.rsplit("/", 1)[0] |  | ||||||
|         g.targetName = targetPath.rsplit("/", 1)[1] |  | ||||||
|     if not os.path.isdir(g.targetDir): |  | ||||||
|         print("Target directory not found.") |  | ||||||
|         sys.exit(2) |  | ||||||
| else: |  | ||||||
|     if not g.DIR: |  | ||||||
|         if not os.path.isdir(args[2]): |  | ||||||
|             print("Target directory not found.") |  | ||||||
|             sys.exit(2) |  | ||||||
|  |  | ||||||
| g.activeDirBlock = 0 |  | ||||||
| g.activeFileName = "" |  | ||||||
| g.activeFileSize = 0 |  | ||||||
| g.activeFileBytesCopied = 0 |  | ||||||
| g.resourceFork = 0 |  | ||||||
| g.PDOSPATH_INDEX = 0 |  | ||||||
|  |  | ||||||
| if (len(args) == 4): |  | ||||||
|     g.PDOSPATH = g.PDOSPATH.replace(':', '/').split('/') |  | ||||||
|     if not g.PDOSPATH[0]: |  | ||||||
|         g.PDOSPATH_INDEX += 1 |  | ||||||
|     g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX] |  | ||||||
|     g.ADdir = (g.targetDir + "/.AppleDouble") |  | ||||||
|     if not ((not g.AD) or os.path.isdir(g.ADdir)): |  | ||||||
|         mkdir(g.ADdir) |  | ||||||
|     processDir(2) |  | ||||||
|     print("ProDOS file not found within image file.") |  | ||||||
|     sys.exit(2) |  | ||||||
| else: |  | ||||||
|     if not g.DIR: |  | ||||||
|         # print(args[0], args[1], args[2]) |  | ||||||
|         g.targetDir = (args[2] + "/" + getVolumeName().decode("L1")) |  | ||||||
|         g.ADdir = (g.targetDir + "/.AppleDouble") |  | ||||||
|         if not os.path.isdir(g.targetDir): |  | ||||||
|             makedirs(g.targetDir) |  | ||||||
|         if not ((not g.AD) or os.path.isdir(g.ADdir)): |  | ||||||
|             makedirs(g.ADdir) |  | ||||||
|     processDir(2) |  | ||||||
|     if not g.DIR: |  | ||||||
|         syncExit() |  | ||||||
|  |  | ||||||
| @@ -1,286 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # mkatinit by Ivan Drucker, http://appleii.ivanx.com |  | ||||||
| # not licensed; please modify and redistribute as you like |  | ||||||
| # 1.0b4 1-30-11 |  | ||||||
|  |  | ||||||
| # 1.1d1 -- uses bashByter. NOT TESTED. |  | ||||||
|  |  | ||||||
| # This script creates the ATINIT file required for netbooting Apple IIe and |  | ||||||
| #   IIGS clients from a netatalk server. ATINIT is put in the in the |  | ||||||
| #   (sharename)/USERS hierarchy, or the current directory if it can't. |  | ||||||
| #   The user can specify the ProDOS startup system program and default prefix. |  | ||||||
| #   If an argument is supplied, it is used as the username and the prompt is |  | ||||||
| #   skipped. |  | ||||||
|  |  | ||||||
| # The ATINIT file is not as complete as the ones generated by AppleShare 3.0, |  | ||||||
| #   and features such as default printer are not used. |  | ||||||
|  |  | ||||||
| # to do |  | ||||||
| # possibly require confirmation if AFPD_GUEST is not set correctly |  | ||||||
| #  or offer to change it |  | ||||||
|  |  | ||||||
| # from ID-bashByter library |  | ||||||
| decToChar () { |  | ||||||
| # converts single-byte decimal value to equivalent character |  | ||||||
| # arg: decimal number from 0-255 |  | ||||||
| # out: one character |  | ||||||
| #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg |  | ||||||
|     [[ $1 ]] || return 11 |  | ||||||
|     [[ $2 ]] && return 8 |  | ||||||
|     [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ |  | ||||||
|      && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 |  | ||||||
|     # args are valid |  | ||||||
|     echo -n -e "\x$(printf %02X "$1")" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| writechars () { |  | ||||||
| # write one or more characters (bytes) to file |  | ||||||
| # arg1: filename |  | ||||||
| # arg2: (optional) offset (# of bytes to skip before writing) |  | ||||||
| # arg3 OR stdin: sequence of characters |  | ||||||
| #  [stdin required if writing NUL (0) or trailing LF (0x0A) chars] |  | ||||||
| #  out: nothing |  | ||||||
| # exit: 8=extraneous arg, 11=missing arg1, |  | ||||||
| #       13=missing stdin/arg3, 22=invalid arg2 |  | ||||||
|     [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } |  | ||||||
|     [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ |  | ||||||
|      ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } |  | ||||||
|     [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } |  | ||||||
|     [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } |  | ||||||
|     # args are valid |  | ||||||
|     if [[ -t 0 ]]; then |  | ||||||
|         echo -n "$3" | \ |  | ||||||
|          dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null |  | ||||||
|     else |  | ||||||
|         dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null |  | ||||||
|     fi |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #---- mkatinit starts here |  | ||||||
| IFS='' |  | ||||||
|  |  | ||||||
| #defaults |  | ||||||
| sharepath=$(grep options:prodos /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) |  | ||||||
| prefix=/$(grep options:prodos /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f2) |  | ||||||
| gsprefix=$prefix |  | ||||||
| startprog="$prefix/BASIC.SYSTEM" |  | ||||||
| gsstartprog="$prefix/SYSTEM/FINDER" |  | ||||||
| filename="ATINIT" |  | ||||||
| user=$(whoami) |  | ||||||
|  |  | ||||||
| echo |  | ||||||
|  |  | ||||||
| usersfolder=1 |  | ||||||
| while [ -n "$1" ] && [ "${1:0:1}" = '-' ]; do |  | ||||||
| 	flag="$1" |  | ||||||
| 	if [ $flag = "-gs" ]; then |  | ||||||
| 		gs=1 |  | ||||||
| 		shift |  | ||||||
| 		continue |  | ||||||
| 	elif [ $flag = "-d" ]; then |  | ||||||
| 		noprompt=1 |  | ||||||
| 		shift |  | ||||||
| 		continue |  | ||||||
| 	elif [ $flag = "-f" ]; then |  | ||||||
| 		overwrite=1 |  | ||||||
| 		shift |  | ||||||
| 		continue |  | ||||||
| 	elif [ $flag = "-g" ]; then |  | ||||||
| 		alsoguest=1 |  | ||||||
| 		shift |  | ||||||
| 		continue |  | ||||||
| 	elif [ $flag = "-c" ]; then |  | ||||||
| 		usersfolder=0 |  | ||||||
| 		shift |  | ||||||
| 		continue |  | ||||||
| 	else |  | ||||||
| 		badflag=1 |  | ||||||
| 		break	 |  | ||||||
| 	fi |  | ||||||
| done |  | ||||||
|  |  | ||||||
| if [ $usersfolder -eq 0 ] && [ -n "$alsoguest" ]; then |  | ||||||
| 	badflag=1 |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| if [ $badflag ]; then |  | ||||||
| 	echo "usage: mkatinit [-gs] [-d] [-f] [-g | -c] [<username>|guest]" |  | ||||||
| 	echo |  | ||||||
| 	echo "<username> should be the name of a netatalk user, or 'guest'" |  | ||||||
| 	echo "-gs sets the default ProDOS netboot system startup program and" |  | ||||||
| 	echo "      prefix for GS/OS (if omitted, ProDOS 8 defaults are used)" |  | ||||||
| 	echo "-d  use the default start program and prefix, without prompting" |  | ||||||
| 	echo "-f  overwrite existing ATINIT file if present, without warning" |  | ||||||
| 	echo "-g  create an ATINIT file for Guest as well as the specified user" |  | ||||||
| 	echo "-c  write ATNIT to current directory instead of USERS hierarchy" |  | ||||||
| 	echo |  | ||||||
| 	exit |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| arg="$1" |  | ||||||
|  |  | ||||||
| [[ -z $arg ]] && arg=$user |  | ||||||
|  |  | ||||||
| while : ; do |  | ||||||
|  |  | ||||||
| 	if [ ${#arg} -gt 32 ]; then |  | ||||||
| 		echo "User name is too long. Exiting with no action." |  | ||||||
| 		exit |  | ||||||
| 	elif [ -n "$arg" ]; then |  | ||||||
| 		if [ `echo $arg | tr '[:upper:]' '[:lower:]'` = "guest" ]; then |  | ||||||
| 			username='<Any User>' |  | ||||||
| 			alsoguest= |  | ||||||
| 			if [[ ! $(grep -F -s $(ls -1 /home) /etc/default/netatalk) ]]; then |  | ||||||
| 				echo 'Warning: The AFPD_GUEST setting in /etc/default/netatalk is not assigned to a' |  | ||||||
| 				echo 'user with a folder in /home. Guest users may be able to boot over the network' |  | ||||||
| 				echo 'into ProDOS 8 for read-only access, but will not be able to boot into GS/OS.' |  | ||||||
| 				if [ $gs ]; then |  | ||||||
| 					echo ' Using ProDOS 8 defaults.' |  | ||||||
| 					gs= |  | ||||||
| 				else |  | ||||||
| 					echo |  | ||||||
| 				fi |  | ||||||
| 				echo |  | ||||||
| 			fi |  | ||||||
| 		else |  | ||||||
| 			username="$arg" |  | ||||||
| 			if [[ ! $(ls -1 /home | grep -F -s $username) ]]; then |  | ||||||
| 				echo "Warning: This username ($username) does not have a folder in /home. This user may" |  | ||||||
| 				echo "not be able to boot over the network into ProDOS 8 or GS/OS." |  | ||||||
| 				echo |  | ||||||
| 			fi |  | ||||||
| 		fi |  | ||||||
| 		if [ $gs ]; then |  | ||||||
| 			startprog="$gsstartprog" |  | ||||||
| 			prefix="$gsprefix" |  | ||||||
| 		fi |  | ||||||
| 	fi |  | ||||||
| 	 |  | ||||||
| 	# make username all caps |  | ||||||
| 	username=`echo $username | tr '[:lower:]' '[:upper:]'` |  | ||||||
| 	 |  | ||||||
| 	# prompt for folders |  | ||||||
| 	if [ ! $doalsoguest ] && [ ! $noprompt ]; then |  | ||||||
| 		while : ; do |  | ||||||
| 			echo "Enter the ProDOS path to the startup system program." |  | ||||||
| 			echo "default (CR to accept): $startprog" |  | ||||||
| 			read |  | ||||||
| 			if [ ${#REPLY} -gt 64 ]; then |  | ||||||
| 				continue |  | ||||||
| 			elif [ -n "$REPLY" ]; then |  | ||||||
| 				startprog="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" |  | ||||||
| 				echo |  | ||||||
| 			fi |  | ||||||
| 			break |  | ||||||
| 		done |  | ||||||
| 		 |  | ||||||
| 		while : ; do |  | ||||||
| 			echo "Enter the initial ProDOS prefix:" |  | ||||||
| 			echo "default (CR to accept): $prefix" |  | ||||||
| 			read |  | ||||||
| 			if [ ${#REPLY} -gt 64 ]; then |  | ||||||
| 				continue |  | ||||||
| 			elif [ -n "$REPLY" ]; then |  | ||||||
| 				prefix="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" |  | ||||||
| 				echo |  | ||||||
| 			fi |  | ||||||
| 			break |  | ||||||
| 		done |  | ||||||
| 	fi |  | ||||||
| 		 |  | ||||||
| 	# create folders if needed |  | ||||||
| 	filepath="$PWD/$filename" |  | ||||||
| 	 |  | ||||||
| 	while [ $usersfolder -eq 1 ]; do |  | ||||||
| 		# create folders for ATINIT |  | ||||||
| 		while [ ! -d "$sharepath" ]; do |  | ||||||
| 			echo "Shared volume '$sharepath' not found. Edit mkatinit to change the default." |  | ||||||
| 			echo "Enter the local path to the netatalk shared volume used for netboot:" |  | ||||||
| 			read sharepath |  | ||||||
| 		done |  | ||||||
| 	 |  | ||||||
| 		if [ ! -d "$sharepath/USERS" ]; then |  | ||||||
| 			mkdir "$sharepath/USERS" |  | ||||||
| 			if [ $? -ne 0 ]; then |  | ||||||
| 				break |  | ||||||
| 			fi |  | ||||||
| 		fi |  | ||||||
| 		if [ ! -d "$sharepath/USERS/$username" ]; then |  | ||||||
| 			mkdir "$sharepath/USERS/$username" |  | ||||||
| 			if [ $? -ne 0 ]; then |  | ||||||
| 				break |  | ||||||
| 			fi |  | ||||||
| 		fi |  | ||||||
| 		if [ ! -d "$sharepath/USERS/$username/SETUP" ]; then |  | ||||||
| 			mkdir "$sharepath/USERS/$username/SETUP" |  | ||||||
| 			if [ $? -ne 0 ]; then |  | ||||||
| 				break |  | ||||||
| 			fi |  | ||||||
| 		else |  | ||||||
| 			if [ ! -w "$sharepath/USERS/$username/SETUP" ]; then |  | ||||||
| 				break |  | ||||||
| 			fi |  | ||||||
| 		fi |  | ||||||
| 		 |  | ||||||
| 		# we have a valid USERS folder target for ATINIT |  | ||||||
| 		filepath="$sharepath/USERS/$username/SETUP/$filename" |  | ||||||
| 		usersfolder=2 |  | ||||||
| 	done |  | ||||||
| 	 |  | ||||||
| 	if [ $usersfolder -eq 1 ]; then |  | ||||||
| 		echo "Could not write to shared volume. Creating ATINIT in current directory." |  | ||||||
| 		if [ -n "$alsoguest" ]; then |  | ||||||
| 			echo "ATINIT for Guest user will not be created." |  | ||||||
| 		fi |  | ||||||
| 		echo |  | ||||||
| 		alsoguest= |  | ||||||
| 	fi |  | ||||||
|  |  | ||||||
| 	if [ ! $doalsoguest ]; then |  | ||||||
| 		echo "netboot start program: $startprog" |  | ||||||
| 		echo "netboot start prefix : $prefix" |  | ||||||
| 		echo |  | ||||||
| 	fi |  | ||||||
| 	 |  | ||||||
| 	#remove ATINIT if present |  | ||||||
| 	if [ ! $overwrite ] && [ -f "$filepath" ]; then |  | ||||||
| 		echo -n "$filepath already exists. Overwrite? " |  | ||||||
| 		while read -s -n 1 > /dev/null 2>&1; do |  | ||||||
| 			if [ -z "$REPLY" ]; then |  | ||||||
| 				continue |  | ||||||
| 			elif [ "$REPLY" = "Y" ] || [ "$REPLY" = "y" ]; then |  | ||||||
| 				echo |  | ||||||
| 				break |  | ||||||
| 			elif [ "$REPLY" = "N" ] || [ "$REPLY" = "n" ]; then |  | ||||||
| 				echo |  | ||||||
| 				echo "Exiting with no action." |  | ||||||
| 				exit |  | ||||||
| 			fi |  | ||||||
| 		done |  | ||||||
| 	fi |  | ||||||
| 	 |  | ||||||
| 	#write the file. start with zeroes |  | ||||||
| 	dd if=/dev/zero of="$filepath" bs=1 count=276 2> /dev/null |  | ||||||
| 	#put in startprog, prefix, username (first byte of each field is length) |  | ||||||
| 	# ( echo -n "${#startprog}" | awk '{printf("%c",$0);}'; echo -n "$startprog"; ) | dd of="$filepath" bs=1 seek=7 conv=notrunc 2> /dev/null |  | ||||||
| 	# ( echo -n "${#prefix}" | awk '{printf("%c",$0);}'; echo -n "$prefix"; ) | dd of="$filepath" bs=1 seek=78 conv=notrunc 2> /dev/null |  | ||||||
| 	# ( echo -n "${#username}" | awk '{printf("%c",$0);}'; echo -n "$username"; ) | dd of="$filepath" bs=1 seek=143 conv=notrunc 2> /dev/null |  | ||||||
| 	( decToChar "${#startprog}"; echo -n "$startprog"; ) | writechars "$filepath" 7 |  | ||||||
| 	( decToChar "${#prefix}"; echo -n "$prefix"; ) | writechars "$filepath" 78 |  | ||||||
| 	( decToChar "${#username}"; echo -n "$username"; ) | writechars "$filepath" 143 |  | ||||||
| 	 |  | ||||||
| 	echo "Created $filepath" |  | ||||||
| 	if [ ! $alsoguest ]; then |  | ||||||
| 		break |  | ||||||
| 	fi |  | ||||||
|  |  | ||||||
| 	if [ $usersfolder -eq 2 ]; then |  | ||||||
| 		usersfolder=1 |  | ||||||
| 	fi |  | ||||||
| 	doalsoguest=1 |  | ||||||
| 	arg='guest' |  | ||||||
| done |  | ||||||
|  |  | ||||||
| echo |  | ||||||
|  |  | ||||||
| @@ -1,82 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # mkvolinfo -- creates a (share)/.AppleDesktop/.volinfo file |  | ||||||
|  |  | ||||||
| makeVolInfoFile () { |  | ||||||
|     [[ -d $sharepath/.AppleDesktop ]] || mkdir $sharepath/.AppleDesktop |  | ||||||
|     touch $volinfo |  | ||||||
|     echo 'MAC_CHARSET:MAC_ROMAN' >> $volinfo |  | ||||||
|     echo 'VOL_CHARSET:UTF8' >> $volinfo |  | ||||||
|     echo 'ADOUBLE_VER:v2' >> $volinfo |  | ||||||
|     echo 'CNIDBACKEND:dbd' >> $volinfo |  | ||||||
|     echo 'CNIDDBDHOST:localhost' >> $volinfo |  | ||||||
|     echo 'CNIDDBDPORT:4700' >> $volinfo |  | ||||||
|     echo "CNID_DBPATH:$sharepath" >> $volinfo |  | ||||||
|     echo 'VOLUME_OPTS:PRODOS CACHEID' >> $volinfo |  | ||||||
|     if (( $mixedcase )); then |  | ||||||
|         echo 'VOLCASEFOLD:' >> $volinfo |  | ||||||
|     else |  | ||||||
|         echo 'VOLCASEFOLD:MTOULOWER UTOMUPPER' >> $volinfo |  | ||||||
|     fi |  | ||||||
|     echo 'EXTATTRTYPE:AFPVOL_EA_AD' >> $volinfo |  | ||||||
|     echo ".volinfo for $sharepath has been created." |  | ||||||
| } |  | ||||||
|  |  | ||||||
| while [[ $1 == "-f" || $1 == "-c" ]]; do |  | ||||||
|     if [[ $1 == "-f" ]]; then |  | ||||||
|         force=1 |  | ||||||
|         shift |  | ||||||
|     fi |  | ||||||
|      |  | ||||||
|     if [[ $1 == "-c" ]]; then |  | ||||||
|         mixedcase=1 |  | ||||||
|         shift |  | ||||||
|     fi |  | ||||||
| done |  | ||||||
|  |  | ||||||
| if [[ ${1:0:1} == "-" ]]; then |  | ||||||
|  |  | ||||||
|     echo "usage: mkvolinfo [-f] [-c] [shared volume path]" |  | ||||||
|     echo |  | ||||||
|     echo "-c will create the .volinfo file to specify no uppercase filename conversion" |  | ||||||
|     echo "-f will create the .volinfo file without prompting, if none exists" |  | ||||||
|     echo "If a path is specified, that is what is used, otherwise the last entry" |  | ||||||
|     echo "in /usr/local/etc/netatalk/AppleVolumes.default is used." |  | ||||||
|  |  | ||||||
| else |  | ||||||
|     sudo true |  | ||||||
|     if [[ $1 ]]; then |  | ||||||
|         sharepath=$(readlink -m $1) |  | ||||||
|     else |  | ||||||
|         sharepath=$(grep ^/media /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) |  | ||||||
|     fi |  | ||||||
|  |  | ||||||
|     volinfo=$sharepath/.AppleDesktop/.volinfo |  | ||||||
|  |  | ||||||
|     if [[ ! -d $sharepath ]]; then |  | ||||||
|         echo "$sharepath does not exist." |  | ||||||
|     else |  | ||||||
|         if [[ -f $volinfo ]]; then |  | ||||||
|             echo "$volinfo already exists." |  | ||||||
|         else |  | ||||||
|             if [[ $force ]]; then |  | ||||||
|                 makeVolInfoFile |  | ||||||
|             else |  | ||||||
|                 echo "The .volinfo file is automatically generated when you first" |  | ||||||
|                 echo "log in from an AFP (Apple II or Mac) client machine." |  | ||||||
|                 echo "If you can't do this, you can create a .volinfo file now" |  | ||||||
|                 echo "based on assumed defaults; proceed with caution if you have" |  | ||||||
|                 echo "customized your AppleVolumes files." |  | ||||||
|                 echo |  | ||||||
|                 echo "If the path shown below is incorrect, you can specify" |  | ||||||
|                 echo "the path to your shared volume as an argument to mkvolinfo." |  | ||||||
|                 echo |  | ||||||
|                 echo -n "Make .volinfo for shared volume $sharepath now? " |  | ||||||
|                 read |  | ||||||
|                 if [[ ${REPLY:0:1} == "y" ]] || [[ ${REPLY:0:1} == "Y" ]]; then |  | ||||||
|                     makeVolInfoFile |  | ||||||
|                 fi |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
| @@ -1,285 +0,0 @@ | |||||||
| # A2SERVER master setup script, last update 15-Feb-2015 |  | ||||||
| # it downloads and executes several scripts related to the setup of |  | ||||||
| # netatalk configured for Apple II use on Debian, Raspbian, or Ubuntu. |  | ||||||
| # more info is at http://appleii.ivanx.com/a2server |  | ||||||
|  |  | ||||||
| # to download and execute, type: |  | ||||||
| # wget appleii.ivanx.com/a2server/setup; source setup |  | ||||||
|  |  | ||||||
| a2serverVersion="124" |  | ||||||
|  |  | ||||||
| isRpi= |  | ||||||
| [[ -f /usr/bin/raspi-config ]] && isRpi=1 |  | ||||||
|  |  | ||||||
| isDebian= |  | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1-2 < /etc/debian_version) == "7." ) && ( $(uname -m) == "i686" ) ]] && isDebian=1 |  | ||||||
|  |  | ||||||
| if [[ -f /usr/local/etc/A2SERVER-version ]]; then |  | ||||||
|     echo "A2SERVER version available: $a2serverVersion" |  | ||||||
|     echo "A2SERVER version installed: $(cat /usr/local/etc/A2SERVER-version)" |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| skipRepoUpdate= |  | ||||||
| autoAnswerYes= |  | ||||||
| setupNetBoot= |  | ||||||
| setupWindowsSharing= |  | ||||||
| updateRasppleII= |  | ||||||
| while [[ $1 ]]; do |  | ||||||
|     if [[ $1 == "-r" ]]; then |  | ||||||
|         shift |  | ||||||
|         skipRepoUpdate="-r" |  | ||||||
|         touch /tmp/a2server-packageReposUpdated |  | ||||||
|     elif [[ $1 == "-y" ]]; then |  | ||||||
|         shift |  | ||||||
|         autoAnswerYes="-y" |  | ||||||
|         touch /tmp/a2server-autoAnswerYes |  | ||||||
|     elif [[ $1 == "-b" ]]; then |  | ||||||
|         shift |  | ||||||
|         setupNetBoot="-b" |  | ||||||
|         touch /tmp/a2server-setupNetBoot |  | ||||||
|     elif [[ $1 == "-w" ]]; then |  | ||||||
|         shift |  | ||||||
|         setupWindowsSharing="-w" |  | ||||||
|         touch /tmp/a2server-setupWindowsSharing |  | ||||||
|     elif [[ $1 == "-os" || $1 == "os" ]]; then |  | ||||||
|     # elif [[ ${1,,} == "rasppleii" || ${1,,} == "raspple" || ${1,,} == "rasappleii" || ${1,,} == "rasapple" || ${1,,} == "raspple2" || ${1,,} == "rasapple2" ]]; then |  | ||||||
|         shift |  | ||||||
|         updateRasppleII=1 |  | ||||||
|     elif [[ $1 == "-v" ]]; then |  | ||||||
|         shift |  | ||||||
|         if [[ ! -f /usr/local/etc/A2SERVER-version ]]; then |  | ||||||
|             echo "A2SERVER version available: $a2serverVersion" |  | ||||||
|             echo "A2SERVER version installed: none" |  | ||||||
|         fi |  | ||||||
|         [[ $0 == "-bash" ]] && return 1 || exit 1 |  | ||||||
|     elif [[ $1 ]]; then |  | ||||||
|         echo "options:" |  | ||||||
|         echo "-v: display installed and available versions, then exit" |  | ||||||
|         echo "-y: auto-answer yes to all prompts" |  | ||||||
|         echo "-r: don't update package repositories" |  | ||||||
|         echo "-b: auto-setup network boot (use with -y)" |  | ||||||
|         echo "-w: auto-setup Windows file sharing (use with -y)" |  | ||||||
|         if [[ $isRpi ]]; then |  | ||||||
|             echo "-os: update Raspbian OS, A2CLOUD, A2SERVER, and Apple II Pi" |  | ||||||
|         fi |  | ||||||
|         [[ $0 == "-bash" ]] && return 1 || exit 1 |  | ||||||
|     fi |  | ||||||
| done |  | ||||||
|  |  | ||||||
| if [[ $updateRasppleII ]]; then |  | ||||||
|     echo "A2SERVER: Updating Raspple II (takes up to an hour)..." |  | ||||||
|     wget -qO /tmp/raspbian-update ivanx.com/a2server/files/raspbian-update.txt |  | ||||||
|     source /tmp/raspbian-update a2cloud a2server $autoAnswerYes $skipRepoUpdate |  | ||||||
|     [[ $0 == "-bash" ]] && return 0 || exit 0 |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| if { [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(cat /usr/local/etc/A2SERVER-version) < 110 )); }; then |  | ||||||
|     echo |  | ||||||
|     echo "WARNING: The current A2SERVER installer scripts haven't been tested for" |  | ||||||
|     echo "updating the earlier version of A2SERVER that you have. A fresh install" |  | ||||||
|     echo "is suggested. Continuing is not recommended and could make A2SERVER" |  | ||||||
|     echo "no longer work properly, or cause data to be lost." |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| a2server_update=0 |  | ||||||
| doSetup=1 |  | ||||||
|  |  | ||||||
| unsupportedOS=1 |  | ||||||
| if [[ $isRpi ]]; then #supported Raspbian? (16-Feb-15, 20-Jun-14, 09-Jan-14, etc) |  | ||||||
|     fwhash=$(zcat /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | grep -m 1 'as of' | awk '{print $NF}') |  | ||||||
|     [[ ($fwhash == "8aca5762") || ($fwhash == "462f3e3f476f7b6") || ($fwhash == "c32bc633039cd9") || ($fwhash == "9d34d0475f9") || ($fwhash == "d4f5315cfac4e") || ($fwhash == "6f4a90c8cb8817f") || ($fwhash == "5dd9b4962e") || ($fwhash == "17c8799375") ]] && unsupportedOS=0 |  | ||||||
| elif [[ "$(lsb_release -rs 2> /dev/null)" == "12.04" ]]; then #Ubuntu 12.04? |  | ||||||
|         unsupportedOS=0 |  | ||||||
| elif [[ "$(lsb_release -rs 2> /dev/null)" == "7.3" || "$(lsb_release -rs 2> /dev/null)" == "7.6" || "$(lsb_release -rs 2> /dev/null)" == "7.8" ]]; then # tested Debian? |  | ||||||
|         unsupportedOS=0 |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| if (( unsupportedOS )); then |  | ||||||
|     echo |  | ||||||
|     echo "WARNING: A2SERVER and its installer scripts have not been tested on this" |  | ||||||
|     echo "operating system version. Continuing is probably fine, but might not be." |  | ||||||
|     echo "Worst case could make your operating system no longer work properly," |  | ||||||
|     echo "or cause data to be lost." |  | ||||||
|     echo "More information is at http://appleii.ivanx.com/a2server."       |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| doSetup=1 |  | ||||||
| if [[ ! -f /usr/local/etc/a2server-help.txt ]] || (( $a2server_update )); then |  | ||||||
| 	echo |  | ||||||
| 	echo "Setting up A2SERVER will take up to 60 minutes, during which" |  | ||||||
| 	echo "you'll see a bunch of stuff spit out across the screen." |  | ||||||
| 	echo |  | ||||||
| 	if [[ ! $autoAnswerYes ]]; then |  | ||||||
|     	echo -n "Ready to set up A2SERVER? " |  | ||||||
| 	    read |  | ||||||
|     	[[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; doSetup=$(( 1 - $? )) |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| if (( $doSetup )); then |  | ||||||
|  |  | ||||||
|     echo |  | ||||||
|     echo "a2server-setup modifies files and performs actions as the root user." |  | ||||||
|     echo "For details, visit http://appleii.ivanx.com/a2server." |  | ||||||
|     echo |  | ||||||
| 	if [[ ! $autoAnswerYes ]]; then |  | ||||||
|         echo -n "Continue? " |  | ||||||
|         read |  | ||||||
|         [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; doSetup=$(( 1 - $? )) |  | ||||||
|     fi |  | ||||||
|      |  | ||||||
|     if (( $doSetup )); then |  | ||||||
|  |  | ||||||
|         userPw=$(sudo grep "^$USER" /etc/shadow | cut -f 2 -d ':') |  | ||||||
|         [[ $userPw == "$(echo 'apple2' | perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isApple2Pw=1 || isApple2Pw= |  | ||||||
|         [[ $userPw == "$(echo 'raspberry' | perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "${userPw%"${userPw#\$*\$*\$}"}")" ]] && isRaspberryPw=1 || isRaspberryPw= |  | ||||||
|  |  | ||||||
|         password="your password" |  | ||||||
|         [[ $isApple2Pw ]] && password="'apple2'" |  | ||||||
|         [[ $isRaspberryPw ]] && password="'raspberry'" |  | ||||||
|                  |  | ||||||
|  |  | ||||||
|         [[ $isRpi ]] && a2server="your Raspberry Pi" || a2server="A2SERVER" |  | ||||||
|         if [[ ! $isApple2Pw && ! -f /usr/local/etc/A2SERVER-version ]]; then |  | ||||||
|             if [[ ! $autoAnswerYes ]]; then |  | ||||||
|                 echo |  | ||||||
|                 echo "To ensure that all client computers are able to connect to" |  | ||||||
|                 echo "${a2server} using the same password, you are recommended" |  | ||||||
|                 echo "to change your user password to 'apple2'." |  | ||||||
|                 echo |  | ||||||
|                 echo -n "Do you want to change the password for user '$USER' to 'apple2' now? " |  | ||||||
|                 read |  | ||||||
|             fi |  | ||||||
|             if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|                 echo "A2SERVER: changing password for user '$USER' to 'apple2'..." |  | ||||||
|                 echo "$USER:apple2" | sudo chpasswd |  | ||||||
|             fi |  | ||||||
|         fi |  | ||||||
|  |  | ||||||
|         echo |  | ||||||
|         echo "During this installation, enter ${password} if prompted for passwords." |  | ||||||
|         echo |  | ||||||
|  |  | ||||||
|         sudo true |  | ||||||
|      |  | ||||||
|         echo |  | ||||||
|         echo "A2SERVER: Downloading scripts..." |  | ||||||
|                  |  | ||||||
|         wget -q -O /tmp/1.storage appleii.ivanx.com/a2server/scripts/a2server-1-storage.txt |  | ||||||
|         chmod ugo+x /tmp/1.storage |  | ||||||
|          |  | ||||||
|         wget -q -O /tmp/2.tools appleii.ivanx.com/a2server/scripts/a2server-2-tools.txt |  | ||||||
|         chmod ugo+x /tmp/2.tools |  | ||||||
|  |  | ||||||
|         wget -q -O /tmp/3.sharing appleii.ivanx.com/a2server/scripts/a2server-3-sharing.txt |  | ||||||
|         chmod ugo+x /tmp/3.sharing |  | ||||||
|                  |  | ||||||
|         wget -q -O /tmp/5.netboot appleii.ivanx.com/a2server/scripts/a2server-5-netboot.txt |  | ||||||
|         chmod ugo+x /tmp/5.netboot |  | ||||||
|          |  | ||||||
|         wget -q -O /tmp/6.samba appleii.ivanx.com/a2server/scripts/a2server-6-samba.txt |  | ||||||
|         chmod ugo+x /tmp/6.samba |  | ||||||
|    |  | ||||||
|         wget -q -O /tmp/7.console appleii.ivanx.com/a2server/scripts/a2server-7-console.txt |  | ||||||
|         chmod ugo+x /tmp/7.console |  | ||||||
|  |  | ||||||
|         echo "A2SERVER: Scripts have been downloaded. Installing..." |  | ||||||
|          |  | ||||||
|         /tmp/1.storage |  | ||||||
|         rm /tmp/1.storage |  | ||||||
|         /tmp/2.tools |  | ||||||
|         rm /tmp/2.tools |  | ||||||
|         /tmp/3.sharing |  | ||||||
|         rm /tmp/3.sharing |  | ||||||
|         /tmp/5.netboot |  | ||||||
|         rm /tmp/5.netboot |  | ||||||
|         /tmp/6.samba |  | ||||||
|         rm /tmp/6.samba |  | ||||||
|         /tmp/7.console |  | ||||||
|         rm /tmp/7.console |  | ||||||
|         rm /tmp/a2server-packageReposUpdated &> /dev/null |  | ||||||
|          |  | ||||||
|         if [[ ! -f /usr/local/etc/A2SERVER-version ]] \ |  | ||||||
|         || (( $(cat /usr/local/etc/A2SERVER-version) < "$a2serverVersion" )); then |  | ||||||
|             echo "$a2serverVersion" | sudo tee /usr/local/etc/A2SERVER-version &> /dev/null |  | ||||||
|         fi |  | ||||||
|  |  | ||||||
|         source /usr/local/etc/a2server-aliases |  | ||||||
|  |  | ||||||
|         # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) |  | ||||||
|         kernelRelease=$(uname -r) |  | ||||||
|         kernelMajorRelease=$(cut -d '.' -f 1 <<< $kernelRelease) |  | ||||||
|         kernelMinorRelease=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') |  | ||||||
|  |  | ||||||
|         # all done, see if AppleTalk is available and notify either way |  | ||||||
|         if [[ $(ps aux | grep [a]talkd) ]]; then |  | ||||||
|             echo "You now have a fully functional file server for Apple II clients." |  | ||||||
|             echo "On an Apple IIe, it should be accessible via \"Log In\" on the" |  | ||||||
|             echo "Workstation Card software. For IIgs users, it should be accessible" |  | ||||||
|             echo "via the AppleShare control panel." |  | ||||||
|             echo |  | ||||||
|             echo |  | ||||||
|             echo "A2SERVER setup is complete! Go connect from your Apple II!" |  | ||||||
|             echo |  | ||||||
|         elif [[ -f /tmp/rpiUpdate ]]; then |  | ||||||
|             echo "A2SERVER is now configured, but Apple II clients will not be able" |  | ||||||
|             echo "to connect until you restart your Raspberry Pi." |  | ||||||
|             echo |  | ||||||
|             if [[ ! $autoAnswerYes ]]; then |  | ||||||
|                 echo -n "Restart now? " |  | ||||||
|                 read |  | ||||||
|             fi |  | ||||||
|             if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|                 sudo shutdown -r now |  | ||||||
|                 echo |  | ||||||
|                 echo "A2SERVER: Preparing to restart..." |  | ||||||
|                 while :; do sleep 60; done |  | ||||||
|             fi |  | ||||||
|             rm /tmp/rpiUpdate |  | ||||||
|             echo |  | ||||||
|         elif [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -ge 12 ]]; then |  | ||||||
|             echo "A2SERVER is now configured, but Apple II clients cannot connect" |  | ||||||
|             echo "because of a kernel-crashing bug in Linux kernel 3.12 through 3.15." |  | ||||||
|             echo "You have kernel version $kernelMajorRelease.$kernelMinorRelease." |  | ||||||
|             echo "A2SERVER has disabled AppleTalk networking to prevent crashes." |  | ||||||
|             echo "Please use kernel 3.11 or earlier, or kernel 3.16 or later." |  | ||||||
|             echo |  | ||||||
|         else |  | ||||||
|             echo "A2SERVER is now configured, but Apple II clients cannot connect because" |  | ||||||
|             echo "AppleTalk networking is unavailable. Please make sure that" |  | ||||||
|             echo "your Linux distribution has a loadable AppleTalk kernel module or" |  | ||||||
|             echo "has AppleTalk built into the kernel, and restart your server." |  | ||||||
|             echo "Or, if you previously disabled AppleTalk in A2SERVER, re-enable it" |  | ||||||
|             echo "by typing 'appletalk-on'." |  | ||||||
|             echo |  | ||||||
|         fi |  | ||||||
|          |  | ||||||
|         if [[ -f /tmp/singleUser ]]; then |  | ||||||
|             if [[ ! $autoAnswerYes ]]; then |  | ||||||
|                 echo "Your Raspberry Pi was started in single-user mode in order to" |  | ||||||
|                 echo -n "fix a problem. You should restart to operate normally. Restart now? " |  | ||||||
|                 read |  | ||||||
|             fi |  | ||||||
|             if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then |  | ||||||
|                 sudo shutdown -r now |  | ||||||
|                 echo |  | ||||||
|                 echo "A2SERVER: Preparing to restart..." |  | ||||||
|                 while :; do sleep 60; done |  | ||||||
|             fi |  | ||||||
|             echo |  | ||||||
|         fi |  | ||||||
|          |  | ||||||
|         echo |  | ||||||
|     	echo "Type 'system-shutdown' to turn off A2SERVER." |  | ||||||
|     	echo "Type 'a2server-setup' to configure network boot." |  | ||||||
| 	    echo "Type 'a2server-help' for a list of other commands." |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| unset a2server_update 2> /dev/null |  | ||||||
| unset doSetup 2> /dev/null |  | ||||||
| rm /tmp/a2server-autoAnswerYes 2> /dev/null |  | ||||||
| rm /tmp/a2server-packageReposUpdated 2> /dev/null |  | ||||||
| rm /tmp/a2server-setupNetBoot 2> /dev/null |  | ||||||
| rm /tmp/a2server-setupWindowsSharing 2> /dev/null |  | ||||||
| rm setup &> /dev/null |  | ||||||
| @@ -1,37 +0,0 @@ | |||||||
| currentVersion=124 |  | ||||||
|  |  | ||||||
| if [[ -f /usr/local/etc/A2SERVER-version ]]; then |  | ||||||
| 	installedVersion=$(cat /usr/local/etc/A2SERVER-version) |  | ||||||
| else |  | ||||||
| 	installedVersion=100 |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| autoAnswerYes= |  | ||||||
| for arg in $@; do |  | ||||||
|     if [[ $arg == "-y" ]]; then |  | ||||||
|         autoAnswerYes=1 |  | ||||||
|         break |  | ||||||
|     fi |  | ||||||
| done |  | ||||||
|  |  | ||||||
| echo |  | ||||||
| echo "Update history:" |  | ||||||
| wget -qO- appleii.ivanx.com/a2server/update/versionhistory.txt |  | ||||||
| echo |  | ||||||
| echo "installed version: ${installedVersion:0:1}.${installedVersion:1:1}.${installedVersion:2:1}" |  | ||||||
| echo "current version: ${currentVersion:0:1}.${currentVersion:1:1}.${currentVersion:2:1}" |  | ||||||
| echo |  | ||||||
| if [[ $autoAnswerYes ]]; then |  | ||||||
|     REPLY="y" |  | ||||||
| else |  | ||||||
|     echo -n "Do you want to update (or reinstall) A2SERVER? " |  | ||||||
|     read |  | ||||||
| fi |  | ||||||
| if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then |  | ||||||
|     sudo rm /usr/local/etc/A2SERVER-version &> /dev/null |  | ||||||
|     # sudo rm /usr/local/etc/netatalk/a2boot/* &> /dev/null |  | ||||||
|     wget -q -O /tmp/setup appleii.ivanx.com/a2server/setup; source /tmp/setup "$@" |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| unset currentVersion 2> /dev/null |  | ||||||
| unset installedVersion 2> /dev/null |  | ||||||
| @@ -1,541 +0,0 @@ | |||||||
| #! /usr/bin/env python |  | ||||||
| # vim: set tabstop=4 shiftwidth=4 expandtab filetype=python: |  | ||||||
|  |  | ||||||
| from __future__ import print_function |  | ||||||
|  |  | ||||||
|  |  | ||||||
| import os, sys, subprocess |  | ||||||
| import tempfile |  | ||||||
| import hashlib |  | ||||||
| import shutil |  | ||||||
| import xml.etree.cElementTree as ET |  | ||||||
|  |  | ||||||
| quiet = False |  | ||||||
| verbose = True |  | ||||||
|  |  | ||||||
| disk7_sources = { |  | ||||||
|     "file"    : "Disk_7_of_7-Apple_II_Setup.sea.bin", |  | ||||||
|     "digest"  : "43fbc296ab66da84aadc275b80fd51ec4f7fe986", |  | ||||||
|     "type"    : "sea.bin", |  | ||||||
|     "sources" : [ |  | ||||||
|         ( "Apple", "http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_IIGS_System_6.0.1/Disk_7_of_7-Apple_II_Setup.sea.bin" ), |  | ||||||
|         ( "archive.org", "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" ) |  | ||||||
|     ] |  | ||||||
| } |  | ||||||
|  |  | ||||||
| a2boot_files = [ |  | ||||||
|     { |  | ||||||
|         "unix"     : "Apple ::e Boot Blocks", |  | ||||||
|         "hfsutils" : "Apple_--e_Boot_Blocks.bin", |  | ||||||
|         "netatalk" : "Apple :2f:2fe Boot Blocks", |  | ||||||
|         "digest"   : "cada362ac2eca3ffa506e9b4e76650ba031e0035", |  | ||||||
|         "patches"  : ( |  | ||||||
|             [ |  | ||||||
|                 "Cleartext password login bug", |  | ||||||
|                 (0x4d43, b"\xA8\xA2\x01\xBD\x80\x38\x99\xA0\x38\xC8\xE8\xE0\x09\x90\xF4"), |  | ||||||
|  |  | ||||||
|                 "ProDOS 8 patch: year table, splash date (6.0.3)", |  | ||||||
|                 (0x004f, b"\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5"), |  | ||||||
|                 (0x1b9f, b"\x12\x11\x0b\x10\x0f\x0e\x0d"), |  | ||||||
|             ], |  | ||||||
|             "8cff6ef453533423b34b5b4fefd642441e2ee374", |  | ||||||
|         ), |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "unix"     : "Basic.System", |  | ||||||
|         "hfsutils" : "Basic.System.bin", |  | ||||||
|         "netatalk" : "Basic.System", |  | ||||||
|         "digest"   : "4d53424f1451cd2e874cf792dbdc8cc6735dcd36", |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "unix"     : "ProDOS16 Boot Blocks", |  | ||||||
|         "hfsutils" : "ProDOS16_Boot_Blocks.bin", |  | ||||||
|         "netatalk" : "ProDOS16 Boot Blocks", |  | ||||||
|         "digest"   : "fab829e82e6662ed6aab119ad18e16ded7d43cda", |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "unix"     : "ProDOS16 Image", |  | ||||||
|         "hfsutils" : "ProDOS16_Image.bin", |  | ||||||
|         "netatalk" : "ProDOS16 Image", |  | ||||||
|         "digest"   : "db4608067b9e7877f45eb557971c4d8c45b46be5", |  | ||||||
|         "patches"  : ( |  | ||||||
|             [ |  | ||||||
|                 "Cleartext password login bug", |  | ||||||
|                 (0x5837, b"\xA8\xA2\x01\xBD\x80\x10\x99\xA0\x10\xC8\xE8\xE0\x09\x90\xF4"), |  | ||||||
|  |  | ||||||
|                 "Enable pressing \"8\" during GS/OS netboot to load ProDOS 8", |  | ||||||
|                 (0x0100, b"\x92"), |  | ||||||
|                 (0x0360, b"\x20\x7d\x14"), |  | ||||||
|                 (0x067d, b"\xad\x00\xc0\x29\xff\x00\xc9\xb8\x00\xd0\x06\xa9\x02\x00\x8d\x53\x14\xa9\x10\x0f\x60"), |  | ||||||
|  |  | ||||||
|                 "ProDOS 8 patch: year table, splash date (6.0.3)", |  | ||||||
|                 (0x0c26, b"\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5"), |  | ||||||
|                 (0x1b76, b"\x12\x11\x0b\x10\x0f\x0e\x0d"), |  | ||||||
|             ], |  | ||||||
|             "1f0477030b7e9c809b0a2282896ca66033e7ca9f", |  | ||||||
|         ), |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "unix"     : "p8", |  | ||||||
|         "hfsutils" : "p8.bin", |  | ||||||
|         "netatalk" : "p8", |  | ||||||
|         # 36c288a5272cf01e0a64eed16786258959118e0e  P8 (02-Apr-93, a2setup) |  | ||||||
|         # c99f69c8dbfe79f02c715162fb409aedf52d378a  P8 (06-May-93, 6.0.1) |  | ||||||
|         # Only splash date differs. |  | ||||||
|         "digest"   : "36c288a5272cf01e0a64eed16786258959118e0e", |  | ||||||
|         "patches"  : ( |  | ||||||
|             [ |  | ||||||
|                 # May as well patch the splash as well.  *shrug* |  | ||||||
|                 "ProDOS 8 patch: year table, splash date (6.0.3)", |  | ||||||
|                 (0x0026, b"\xb0\xb2\xad\xc1\xf5\xe7\xad\xb1\xb5"), |  | ||||||
|                 (0x0f76, b"\x12\x11\x0b\x10\x0f\x0e\x0d"), |  | ||||||
|             ], |  | ||||||
|             "ad1e6c8f653df428d13cb8ae5ce4f8425a52016b", |  | ||||||
|         ), |  | ||||||
|     }, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| # True for Python 3.0 and later |  | ||||||
| PY3 = sys.version_info >= (3, 0) |  | ||||||
|  |  | ||||||
| if PY3: |  | ||||||
|     stdin_input = input |  | ||||||
|     import urllib.request as urlrequest |  | ||||||
| else: |  | ||||||
|     stdin_input = raw_input |  | ||||||
|     import urllib2 as urlrequest |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def sha1sum_file (filename, blocksize=65536): |  | ||||||
|     f = open(filename, "rb") |  | ||||||
|     digest = hashlib.sha1() |  | ||||||
|     buf = f.read(blocksize) |  | ||||||
|     while len(buf) > 0: |  | ||||||
|         digest.update(buf) |  | ||||||
|         buf = f.read(blocksize) |  | ||||||
|     f.close() |  | ||||||
|     return digest.hexdigest() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def download_from_sources(fileinfo, output_dir): |  | ||||||
|     output_path = os.path.join(output_dir, fileinfo["file"]) |  | ||||||
|     if not quiet: |  | ||||||
|         print("Downloading %s" % (fileinfo["file"])) |  | ||||||
|     for (source, url) in fileinfo["sources"]: |  | ||||||
|         if not quiet: |  | ||||||
|             print("   From %s..." % (source), end="") |  | ||||||
|  |  | ||||||
|         try: |  | ||||||
|             html = urlrequest.urlopen(url) |  | ||||||
|             data = html.read() |  | ||||||
|             f = open(output_path, "wb") |  | ||||||
|             f.write(data) |  | ||||||
|             f.close() |  | ||||||
|         except: |  | ||||||
|             if not quiet: |  | ||||||
|                 print("  download failed.") |  | ||||||
|             if 'f' in locals(): |  | ||||||
|                 if not f.isclosed(): |  | ||||||
|                     f.close() |  | ||||||
|             continue |  | ||||||
|  |  | ||||||
|         digest = sha1sum_file(output_path) |  | ||||||
|         if digest == fileinfo["digest"]: |  | ||||||
|             if not quiet: |  | ||||||
|                 print("  successfully downloaded.") |  | ||||||
|             return True |  | ||||||
|         else: |  | ||||||
|             if not quiet: |  | ||||||
|                 print("  failed (digest mismatch).") |  | ||||||
|             if verbose: |  | ||||||
|                 print("      Expected: %s\n      Received: %s" |  | ||||||
|                         % (fileinfo["digest"], digest)) |  | ||||||
|  |  | ||||||
|     return False |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Apple's GS/OS 6.0.1 images are stored in MacBinary-wrapped |  | ||||||
| # self-extracting disk image files.  The Unarchiver's unar is able |  | ||||||
| # to unwrap the MacBinary wrapper for us, but we have to extract the |  | ||||||
| # disk image oursselves.  Fortunately, it's uncompressed. |  | ||||||
| def extract_800k_sea_bin(archive_name, image_name, archive_dir): |  | ||||||
|     if not quiet: |  | ||||||
|         print("Extracting %s..." % (archive_name), end="") |  | ||||||
|  |  | ||||||
|     archive_path = os.path.join(archive_dir, archive_name) |  | ||||||
|     image_path = os.path.join(archive_dir, image_name) |  | ||||||
|  |  | ||||||
|     if not os.path.isfile(archive_path): |  | ||||||
|         if not quiet: |  | ||||||
|             print("  not found.") |  | ||||||
|             return False |  | ||||||
|  |  | ||||||
|     # Extract the original filename from the file |  | ||||||
|     # MacBinary II header is 128 bytes.  The first byte is NUL, followed by a |  | ||||||
|     # Pascal string of length 63 (so 64 bytes total) containing the encoded |  | ||||||
|     # filename. |  | ||||||
|     # |  | ||||||
|     # Source: http://files.stairways.com/other/macbinaryii-standard-info.txt |  | ||||||
|     # FIXME: We should eventually implement a full MacBinary reader. |  | ||||||
|  |  | ||||||
|     try: |  | ||||||
|         f = open(archive_path, "rb") |  | ||||||
|         sea_name = f.read(65) |  | ||||||
|         f.close() |  | ||||||
|  |  | ||||||
|         if len(sea_name) < 65: |  | ||||||
|             if not quiet: |  | ||||||
|                 print("  file too short.") |  | ||||||
|             return False |  | ||||||
|  |  | ||||||
|         if PY3: |  | ||||||
|             sea_name = sea_name[2:2 + sea_name[1]].decode("mac_roman") |  | ||||||
|         else: |  | ||||||
|             sea_name = sea_name[2:2 + ord(sea_name[1])] |  | ||||||
|     except: |  | ||||||
|         if not quiet: |  | ||||||
|             print("  error: cannot read expanded name") |  | ||||||
|         if 'f' in locals(): |  | ||||||
|             if not f.isclosed(): |  | ||||||
|                 f.close() |  | ||||||
|         return False |  | ||||||
|  |  | ||||||
|     try: |  | ||||||
|         cmdline = ["unar", "-q", "-o", archive_dir, "-k", "skip", archive_path] |  | ||||||
|         ret = subprocess.call(cmdline) |  | ||||||
|         if ret != 0: |  | ||||||
|             if not quiet: |  | ||||||
|                 print("  error: unar returned error %i" % (ret)) |  | ||||||
|             return False |  | ||||||
|     except OSError as e: |  | ||||||
|         if not quiet: |  | ||||||
|             print("  error: running unar: %s" % (e)) |  | ||||||
|         return False |  | ||||||
|  |  | ||||||
|     sea_path = os.path.join(archive_dir, sea_name) |  | ||||||
|     if not os.path.isfile(sea_path): |  | ||||||
|         if not quiet: |  | ||||||
|             print("  error: \"%s\" was not extracted." % (sea_name)) |  | ||||||
|         return False |  | ||||||
|  |  | ||||||
|     try: |  | ||||||
|         # The image starts 84 bytes in, and is exactly 819200 bytes long |  | ||||||
|         with open(sea_path, "rb") as src, open(image_path, "wb") as dst: |  | ||||||
|             src.seek(84) |  | ||||||
|             dst.write(src.read(819200)) |  | ||||||
|             if dst.tell() != 819200: |  | ||||||
|                 raise IOError() |  | ||||||
|             extracted = True |  | ||||||
|     except: |  | ||||||
|         if not quiet: |  | ||||||
|             print("  error: \"%s\" is not an 800k floppy image" |  | ||||||
|                     % (sea_name)) |  | ||||||
|         extracted = False |  | ||||||
|     finally: |  | ||||||
|         if not quiet: |  | ||||||
|             print("  done.") |  | ||||||
|         os.unlink(sea_path) |  | ||||||
|         os.unlink(archive_path) |  | ||||||
|  |  | ||||||
|     return extracted |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def plist_keyvalue(plist_dict, key): |  | ||||||
|     if plist_dict.tag != "dict": |  | ||||||
|         raise ValueError("not a plist dict") |  | ||||||
|     found = False |  | ||||||
|     for elem in plist_dict: |  | ||||||
|         if found: |  | ||||||
|             return elem |  | ||||||
|         if elem.tag == "key" and elem.text == key: |  | ||||||
|             found = True |  | ||||||
|     return None |  | ||||||
|  |  | ||||||
| def find_mountpoint(xmlstr): |  | ||||||
|     plistroot = ET.fromstring(xmlstr) |  | ||||||
|     if plistroot.tag != "plist": |  | ||||||
|         raise ValueError("xmlstr is not an XML-format plist") |  | ||||||
|     if plistroot[0].tag == "dict": |  | ||||||
|         sys_entities = plist_keyvalue(plistroot[0], "system-entities") |  | ||||||
|         if sys_entities.tag != "array": |  | ||||||
|             raise ValueError("expected dict to contain an array") |  | ||||||
|         for child in sys_entities: |  | ||||||
|             if child.tag == "dict": |  | ||||||
|                 mountpoint = plist_keyvalue(child, "mount-point") |  | ||||||
|                 return mountpoint.text |  | ||||||
|             else: |  | ||||||
|                 raise ValueError("system-entities should be an array of dict objects") |  | ||||||
|     else: |  | ||||||
|         raise ValueError("Root element is not a dict") |  | ||||||
|  |  | ||||||
| a2setup_platform = None |  | ||||||
|  |  | ||||||
| def a2setup_set_platform(): |  | ||||||
|     global a2setup_platform |  | ||||||
|      |  | ||||||
|     a2setup_platform = os.uname()[0] |  | ||||||
|     if a2setup_platform not in ["Linux", "Darwin"]: |  | ||||||
|         a2setup_platform = "hfsutils" |  | ||||||
|     elif a2setup_platform == "Linux": |  | ||||||
|         use_sudo = False |  | ||||||
|         if os.geteuid() != 0: |  | ||||||
|             reply = stdin_input(""" |  | ||||||
| You must have either root access or the hfsutils package to |  | ||||||
| access the disk image containing Apple // boot blocks.  Do |  | ||||||
| you want to mount the image using the sudo command? [y] """) |  | ||||||
|             if reply.startswith("y") or reply.startswith("Y") or reply == "": |  | ||||||
|                 use_sudo = True |  | ||||||
|                 print(""" |  | ||||||
| Okay, if asked for a password, type your user password.  It |  | ||||||
| will not be echoed when you type.""") |  | ||||||
|             else: |  | ||||||
|                 a2setup_platform = "hfsutils" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def a2setup_mount(image_path): |  | ||||||
|     mountpoint = None |  | ||||||
|     if a2setup_platform == "Linux": |  | ||||||
|         mountpoint = tempfile.mkdtemp(prefix = "tmp-hfsmount.") |  | ||||||
|         mount_cmd = ["mount", "-t", "hfs", "-o", "ro,loop", image_path, mountpoint] |  | ||||||
|         if use_sudo: |  | ||||||
|             mount_cmd = ["sudo"] + mount_cmd |  | ||||||
|         subprocess.call(mount_cmd) |  | ||||||
|     elif a2setup_platform == "Darwin": |  | ||||||
|         xmlstr = subprocess.check_output(["hdiutil", "attach", "-plist", |  | ||||||
|                 image_path]) |  | ||||||
|         mountpoint = find_mountpoint(xmlstr) |  | ||||||
|     elif a2setup_platform == "hfsutils": |  | ||||||
|         mountpoint = tempfile.mkdtemp(prefix = "tmp-hfsmount.") |  | ||||||
|         sys_folder = os.path.join(mountpoint, "System Folder") |  | ||||||
|         os.mkdir(sys_folder) |  | ||||||
|         devnull = open(os.devnull, "wb") |  | ||||||
|         subprocess.call(["hmount", image_path], stdout=devnull) |  | ||||||
|         devnull.close() |  | ||||||
|         subprocess.call(["hcopy", "Apple II Setup:System Folder:*", sys_folder]) |  | ||||||
|         subprocess.call(["humount", "Apple II Setup"]) |  | ||||||
|  |  | ||||||
|     return mountpoint |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def a2setup_copyfile(bootfile, mountpoint, dest_dir, dest_fmt): |  | ||||||
|     src_dir = os.path.join(mountpoint, "System Folder") |  | ||||||
|     if a2setup_platform == "Linux" or a2setup_platform == "Darwin": |  | ||||||
|         src_path = os.path.join(src_dir, bootfile["unix"]) |  | ||||||
|     elif a2setup_platform == "hfsutils": |  | ||||||
|         src_path = os.path.join(src_dir, bootfile["hfsutils"]) |  | ||||||
|     dest_path = os.path.join(dest_dir, bootfile[dest_fmt]) |  | ||||||
|     try: |  | ||||||
|         shutil.copyfile(src_path, dest_path) |  | ||||||
|     except: |  | ||||||
|         return False |  | ||||||
|  |  | ||||||
|     return True |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def a2setup_umount(mountpoint): |  | ||||||
|     if a2setup_platform == "Linux": |  | ||||||
|         umount_cmd = ["umount", mountpoint] |  | ||||||
|         if use_sudo: |  | ||||||
|             umount_cmd = ["sudo"] + umount_cmd |  | ||||||
|         subprocess.call(umount_cmd) |  | ||||||
|         os.rmdir(mountpoint) |  | ||||||
|     elif a2setup_platform == "Darwin": |  | ||||||
|         devnull = open(os.devnull, "wb") |  | ||||||
|         subprocess.call(["hdiutil", "eject", mountpoint], stdout=devnull) |  | ||||||
|         devnull.close() |  | ||||||
|     elif a2setup_platform == "hfsutils": |  | ||||||
|         sys_folder = os.path.join(mountpoint, "System Folder") |  | ||||||
|         for f in os.listdir(sys_folder): |  | ||||||
|             os.unlink(os.path.join(sys_folder, f)) |  | ||||||
|         os.rmdir(sys_folder) |  | ||||||
|         os.rmdir(mountpoint) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def apply_patches(bootfile, dest_dir, dest_fmt): |  | ||||||
|     if "patches" in bootfile: |  | ||||||
|         (patches, digest) = bootfile["patches"] |  | ||||||
|         patch_path = os.path.join(dest_dir, bootfile[dest_fmt]) |  | ||||||
|         dest_digest = sha1sum_file(patch_path) |  | ||||||
|         if dest_digest == digest: |  | ||||||
|             if not quiet: |  | ||||||
|                 print("  \"%s\" is already patched." % (bootfile[dest_fmt])) |  | ||||||
|                 return True |  | ||||||
|         else: |  | ||||||
|             if verbose: |  | ||||||
|                 print("  Patching %s..." % (bootfile[dest_fmt])) |  | ||||||
|             elif not quiet: |  | ||||||
|                 print("  Patching %s..." % (bootfile[dest_fmt]), end="") |  | ||||||
|             f = open(patch_path, "r+b") |  | ||||||
|             for patch in patches: |  | ||||||
|                 if isinstance(patch, str): |  | ||||||
|                     if verbose: |  | ||||||
|                         print("    %s" % (patch)) |  | ||||||
|                 else: |  | ||||||
|                     (offset, data) = patch |  | ||||||
|                     f.seek(offset) |  | ||||||
|                     f.write(data) |  | ||||||
|             f.close() |  | ||||||
|  |  | ||||||
|             # Verify... |  | ||||||
|             dest_digest = sha1sum_file(patch_path) |  | ||||||
|             if dest_digest == digest: |  | ||||||
|                 print("  patched.") |  | ||||||
|             else: |  | ||||||
|                 print("  patch failed.\n      Expected: %s\n      Received: %s" |  | ||||||
|                         % (bootfile["patches"][1], dest_digest)) |  | ||||||
|                 return False |  | ||||||
|  |  | ||||||
|     return True |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def install_bootblocks(dest_dir, dest_fmt): |  | ||||||
|     if dest_fmt not in ["unix", "netatalk"]: |  | ||||||
|         raise ValueError("Only basic UNIX and netatalk formats are supported for now") |  | ||||||
|  |  | ||||||
|     if not quiet: |  | ||||||
|         print("Installing Apple // boot blocks...") |  | ||||||
|  |  | ||||||
|     if not os.path.isdir(dest_dir): |  | ||||||
|         os.makedirs(dest_dir, mode=0o0755) |  | ||||||
|  |  | ||||||
|     work_dir = tempfile.mkdtemp(prefix = "tmp-a2sv-bootblocks.") |  | ||||||
|     a2setup_name = "A2SETUP.img" |  | ||||||
|     if verbose: |  | ||||||
|         print("   dest_fmt : %s\n   dest_dir : %s\n   work_dir : %s\n" |  | ||||||
|                 % (dest_fmt, dest_dir, work_dir)) |  | ||||||
|  |  | ||||||
|     a2setup_set_platform() |  | ||||||
|  |  | ||||||
|     a2boot_needed = False |  | ||||||
|     a2setup_extracted = False |  | ||||||
|     a2boot_installed = False |  | ||||||
|  |  | ||||||
|     for bootfile in a2boot_files: |  | ||||||
|         dest_path = os.path.join(dest_dir, bootfile[dest_fmt]) |  | ||||||
|         if not os.path.isfile(dest_path): |  | ||||||
|             a2boot_needed = True |  | ||||||
|             break |  | ||||||
|         else: |  | ||||||
|             dest_digest = sha1sum_file(dest_path) |  | ||||||
|             if dest_digest != bootfile["digest"]: |  | ||||||
|                 if "patches" not in bootfile or dest_digest != bootfile["patches"][1]: |  | ||||||
|                     a2boot_needed = True |  | ||||||
|                     break |  | ||||||
|  |  | ||||||
|     if not a2boot_needed: |  | ||||||
|         if not quiet: |  | ||||||
|             print("Files already copied.") |  | ||||||
|         a2boot_installed = True |  | ||||||
|     else: |  | ||||||
|         if download_from_sources(disk7_sources, work_dir): |  | ||||||
|             if disk7_sources["type"] == "sea.bin": |  | ||||||
|                 a2setup_extracted = extract_800k_sea_bin(disk7_sources["file"], |  | ||||||
|                         a2setup_name, work_dir) |  | ||||||
|             else: |  | ||||||
|                 # Placeholder for 6.0.4+ files packed some other way |  | ||||||
|                 pass |  | ||||||
|  |  | ||||||
|             if a2setup_extracted: |  | ||||||
|                 a2setup_path = os.path.join(work_dir, a2setup_name) |  | ||||||
|                 mountpoint = a2setup_mount(a2setup_path) |  | ||||||
|                 src_dir = os.path.join(mountpoint, "System Folder") |  | ||||||
|  |  | ||||||
|                 if not quiet: |  | ||||||
|                     print("Copying files...", end="") |  | ||||||
|                 a2boot_installed = True |  | ||||||
|                 for bootfile in a2boot_files: |  | ||||||
|                     if not a2setup_copyfile(bootfile, mountpoint, dest_dir, dest_fmt): |  | ||||||
|                         a2boot_installed = False |  | ||||||
|  |  | ||||||
|                 if not quiet: |  | ||||||
|                     if a2boot_installed: |  | ||||||
|                         print("  success.") |  | ||||||
|                     else: |  | ||||||
|                         print("  error copying files") |  | ||||||
|  |  | ||||||
|                 a2setup_umount(mountpoint) |  | ||||||
|                 os.unlink(a2setup_path) |  | ||||||
|  |  | ||||||
|     os.rmdir(work_dir) |  | ||||||
|  |  | ||||||
|     if not a2boot_installed and not quiet: |  | ||||||
|         print("Installation failed.") |  | ||||||
|         return False |  | ||||||
|  |  | ||||||
|     for bootfile in a2boot_files: |  | ||||||
|         apply_patches(bootfile, dest_dir, dest_fmt) |  | ||||||
|  |  | ||||||
|     return True |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def do_install(): |  | ||||||
|     netboot_tmp = tempfile.mkdtemp(suffix = ".a2server-netboot") |  | ||||||
|     print("You'll want to go and delete this directory:") |  | ||||||
|     print(netboot_tmp) |  | ||||||
|     os.chdir(netboot_tmp) |  | ||||||
|  |  | ||||||
|     #   If we need boot files: |  | ||||||
|     #       Download a disk image |  | ||||||
|     #       If it is one we need to unpack (.sea.bin): |  | ||||||
|     #           unar it |  | ||||||
|     #           extract the embedded image |  | ||||||
|     #       If we need to apply boot block patches: |  | ||||||
|     #           fix cleartext password bug in //e boot block |  | ||||||
|     #           fix cleartext password bug in IIgs boot block |  | ||||||
|     #           patch IIgs boot block to allow booting ProDOS 8 |  | ||||||
|     #   If we don't have A2SERVER tools: |  | ||||||
|     #       Download the installer script |  | ||||||
|     #       Run the installer script |  | ||||||
|     #   Copy Basic.System to A2FILES for ProDOS 8 |  | ||||||
|     #   If NETBOOT.P8 (battery ram set to boot into ProDOS 8) doesn't exist: |  | ||||||
|     #       Create it |  | ||||||
|     #   If NETBOOT.GSOS (battery ram set to boot into GSOS) doesn't exist: |  | ||||||
|     #       Create it |  | ||||||
|     #   Set GS/OS to boot SYSTEM/FINDER (registered user or guest) |  | ||||||
|     #   Set ProDOS 8 to boot BASIC.SYSTEM (guest) |  | ||||||
|     #   If SYSTEM/START.GS.OS doesn't exist in A2FILES: |  | ||||||
|     #       Ask if user wants to install GS/OS 6.0.1 |  | ||||||
|     #       If they answer yes: |  | ||||||
|     #           create imagesDir |  | ||||||
|     #           create netInstallDir |  | ||||||
|     #           For each disk: |  | ||||||
|     #               Download the disk |  | ||||||
|     #               If it is one we need to unpack (.sea.bin): |  | ||||||
|     #                   extract_800k_sea_bin it |  | ||||||
|     #               unpack the disk to netInstallDir |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     # XXX Re-enable this |  | ||||||
|     #os.rmdir(netboot_tmp) |  | ||||||
|  |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     # bail out on automated netboot setup unless -b is also specified |  | ||||||
|     # FIXME: This logic belongs in a2server-setup, not here |  | ||||||
|     autoAnswerYes = os.path.isfile("/tmp/a2server-autoAnswerYes") |  | ||||||
|     if autoAnswerYes and not os.path.isfile("/tmp/a2server-setupNetBoot"): |  | ||||||
|         sys.exit(0) |  | ||||||
|  |  | ||||||
|     # We need root to do this.  If we don't have it, just rerun the command with |  | ||||||
|     # sudo and be done with it. |  | ||||||
|     # |  | ||||||
|     # FIXME: Should we be doing this?  A generic installer should not assume it's |  | ||||||
|     # writing to a root-owned dir, nor care.  Probably the reason to do it this way |  | ||||||
|     # is as a proof of concept that it can be done this way in the main |  | ||||||
|     # a2server-setup script, which of course means we don't actually need to change |  | ||||||
|     # the password for the user. |  | ||||||
|     # |  | ||||||
|     # XXX Disabling this for development |  | ||||||
|     """ |  | ||||||
|     if os.geteuid() != 0: |  | ||||||
|         args = sys.argv |  | ||||||
|         args.insert(0, "sudo") |  | ||||||
|         # At the very least, we should print the command line we"re running here |  | ||||||
|         print ("Rerunning with sudo...") |  | ||||||
|         ret = subprocess.call(args) |  | ||||||
|         sys.exit(ret) |  | ||||||
|     """ |  | ||||||
|  |  | ||||||
|     install_bootblocks(os.path.join(os.getcwd(), "a2boot"), "netatalk") |  | ||||||
|     #reply = stdin_input("""\nDo you want to set up A2SERVER to be able to boot Apple II\ncomputers over the network? [y] """) |  | ||||||
|     #if reply.startswith("y") or reply.startswith("Y") or reply == "": |  | ||||||
|     #    do_install() |  | ||||||
							
								
								
									
										1749
									
								
								files/A2FILES-list.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1749
									
								
								files/A2FILES-list.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										66
									
								
								files/dist/getexternal.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										66
									
								
								files/dist/getexternal.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | #! /bin/bash | ||||||
|  | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: | ||||||
|  |  | ||||||
|  | if ! hash wget; then | ||||||
|  |     echo "wget is not installed. On a Mac, install it with MacPorts or Homebrew." | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | echo "Downloading items..." | ||||||
|  |  | ||||||
|  | mkdir -p files/external/source | ||||||
|  | wget -O files/external/source/ciopfs-0.4.tar.gz http://www.brain-dump.org/projects/ciopfs/ciopfs-0.4.tar.gz | ||||||
|  | wget -O files/external/source/macipgw.zip https://github.com/zero2sixd/macipgw/archive/2a5f6a7521a627e46b18468d44f4306fb0a7b7ab.zip | ||||||
|  | wget -O files/external/source/netatalk-2.2.4.tar.gz http://downloads.sourceforge.net/project/netatalk/netatalk/2.2.4/netatalk-2.2.4.tar.gz | ||||||
|  | wget -O files/external/source/nulib2-3.1.0a2.zip https://github.com/fadden/nulib2/archive/20fe7efb4d37fedf807416c16d74d51d893ea48a.zip | ||||||
|  | wget -O files/external/source/unar-1.8.1.zip https://github.com/incbee/Unarchiver/archive/unar-1.8.1.zip | ||||||
|  |  | ||||||
|  | mkdir -p files/external/appleii | ||||||
|  | wget --max-redirect 0 -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 | ||||||
|  | wget -O files/external/appleii/Asimov.shk http://www.ninjaforce.com/downloads/Asimov.shk | ||||||
|  | wget -O files/external/appleii/MOUNTIT.SHK http://www.brutaldeluxe.fr/products/apple2gs/MOUNTIT.SHK | ||||||
|  | wget -O files/external/appleii/Marinetti3.0b8.po http://www.a2retrosystems.com/downloads/Marinetti3.0b8.po | ||||||
|  | wget -O files/external/appleii/PPPX.1.3d4.SHK http://www.apple2.org/marinetti/PPPX.1.3d4.SHK | ||||||
|  | wget -O files/external/appleii/dsk2file.shk http://www.dwheeler.com/6502/oneelkruns/dsk2file.zip | ||||||
|  | wget -O files/external/appleii/gshk11.sea http://www.nulib.com/library/gshk11.sea | ||||||
|  | wget -O files/external/appleii/shrinkit.sdk http://www.nulib.com/library/shrinkit.sdk | ||||||
|  | wget -O files/external/appleii/spectrum_gold_2mg.zip http://www.speccie.co.uk/speccie/software/spectrum_gold_2mg.zip | ||||||
|  | wget -O files/external/appleii/uthernet2ll.bxy http://www.speccie.co.uk/speccie/software/uthernet2ll.bxy | ||||||
|  | wget -O files/external/appleii/uthernetll.bxy http://www.speccie.co.uk/speccie/software/uthernetll.bxy | ||||||
|  |  | ||||||
|  | unset safeUrl samUrl snapUrl safeVer samVer snapVer | ||||||
|  | html=$(wget -qO- http://speccie.co.uk/speccie/Site/Download_Centre_files/widget1_markup.html) | ||||||
|  | safeUrl=$(echo "$html" | grep -i 'safe2.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') | ||||||
|  | samUrl=$(echo "$html" | grep -i 'sam2.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') | ||||||
|  | snapUrl=$(echo "$html" | grep -i 'snap.*bxy' | tr '<>' '\n' | grep href | cut -d '=' -f 2 | tr -d '"') | ||||||
|  | wget -O files/external/appleii/safe2.bxy "$safeUrl" | ||||||
|  | wget -O files/external/appleii/sam2.bxy "$samUrl" | ||||||
|  | wget -O files/external/appleii/snap.bxy "$snapUrl" | ||||||
|  |  | ||||||
|  | for gsosInstall in {1..3}; do | ||||||
|  |     activeDisk=0 | ||||||
|  |     mkdir -p files/external/appleii/gsos60${gsosInstall} | ||||||
|  |  | ||||||
|  |     diskNames=( Install System.Disk SystemTools1 SystemTools2 Fonts synthLAB ) | ||||||
|  |     if (( $gsosInstall == 1 )); then | ||||||
|  |         gsosURL="http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_IIGS_System_6.0.1/" | ||||||
|  |         wget --max-redirect 0 -O files/external/appleii/gsos601/Disk_7_of_7-Apple_II_Setup.sea.bin http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Apple_II/Apple_IIGS_System_6.0.1/Disk_7_of_7-Apple_II_Setup.sea.bin | ||||||
|  |     elif (( $gsosInstall == 2 )); then | ||||||
|  |         gsosURL="http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Software/Operating%20Systems/Apple%20IIGS%20System/Disk%20Images/" | ||||||
|  |         diskNames=( Install System.Disk SystemTools1 SystemTools2 SystemTools3 Fonts1 Fonts2 synthLAB ) | ||||||
|  |         diskWebNames=( Install System%20disk System%20tools%201 System%20tools%202 System%20tools%203 Fonts%201 Fonts%202 Synthlab ) | ||||||
|  |     elif (( $gsosInstall == 3 )); then | ||||||
|  |         gsosURL="ftp://ftp.apple.asimov.net/pub/apple_II/images/gs/os/gsos/Apple_IIGS_System_6.0.3/" | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  |     for diskname in ${diskNames[@]}; do | ||||||
|  |         outfile="files/external/appleii/gsos60${gsosInstall}/$diskname.po" | ||||||
|  |         (( activeDisk++ )) | ||||||
|  |         if (( $gsosInstall == 1 )); then | ||||||
|  |             wget --max-redirect 0 -O files/external/appleii/gsos601/"Disk_${activeDisk}_of_7-${diskname}.sea.bin" "${gsosURL}Disk_${activeDisk}_of_7-${diskname}.sea.bin" | ||||||
|  |         elif (( $gsosInstall == 2 )); then | ||||||
|  |             wget -O $outfile "$gsosURL/IIGS%20System%206.0.2%20-%20Disk%20${activeDisk}%20${diskWebNames[$activeDisk-1]}.po" | ||||||
|  |         elif (( $gsosInstall == 3 )); then | ||||||
|  |             wget -O $outfile "$gsosURL/$diskname.po" | ||||||
|  |         fi | ||||||
|  |     done | ||||||
|  | done | ||||||
							
								
								
									
										152
									
								
								files/netatalk-init.d-clean.txt
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										152
									
								
								files/netatalk-init.d-clean.txt
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,152 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | ### BEGIN INIT INFO | ||||||
|  | # Provides:          netatalk | ||||||
|  | # Required-Start:    $remote_fs $syslog | ||||||
|  | # Should-Start:      avahi-daemon | ||||||
|  | # Required-Stop:     $remote_fs $syslog | ||||||
|  | # Default-Start:     2 3 4 5 | ||||||
|  | # Default-Stop:      1 | ||||||
|  | ### END INIT INFO | ||||||
|  | # | ||||||
|  | # netatalk      Netatalk 2.2.4 initscript | ||||||
|  | # Author:       Thomas Kaiser <Thomas.Kaiser@phg-online.de> | ||||||
|  |  | ||||||
|  | set -e | ||||||
|  |  | ||||||
|  | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin | ||||||
|  | DESC="Netatalk" | ||||||
|  | NAME=netatalk | ||||||
|  | SCRIPTNAME=/etc/init.d/$NAME | ||||||
|  |  | ||||||
|  | # Guard to prevent execution if netatalk was removed. | ||||||
|  | test -x /usr/local/sbin/afpd || exit 0 | ||||||
|  |  | ||||||
|  | # Set defaults. Please change these options in /etc/default/netatalk | ||||||
|  | ATALK_NAME=`/bin/hostname --short` | ||||||
|  | ATALK_UNIX_CHARSET='LOCALE' | ||||||
|  | ATALK_MAC_CHARSET='MAC_ROMAN' | ||||||
|  |  | ||||||
|  | CNID_METAD_RUN=yes | ||||||
|  | AFPD_RUN=yes | ||||||
|  | AFPD_MAX_CLIENTS=50 | ||||||
|  | AFPD_UAMLIST="-U uams_dhx2.so" | ||||||
|  | AFPD_GUEST=nobody | ||||||
|  | CNID_CONFIG="-l log_note" | ||||||
|  |  | ||||||
|  | ATALKD_RUN=no | ||||||
|  | PAPD_RUN=no | ||||||
|  | TIMELORD_RUN=no | ||||||
|  | #A2BOOT_RUN=no | ||||||
|  | ATALK_ZONE= | ||||||
|  | ATALK_BGROUND=no | ||||||
|  |  | ||||||
|  | # old /etc/default/netatalk expected hostname in $HOSTNAME by default | ||||||
|  | HOSTNAME=`/bin/hostname` | ||||||
|  |  | ||||||
|  | # Read in netatalk configuration. | ||||||
|  | if [ -f /etc/default/netatalk ]; then | ||||||
|  |     . /etc/default/netatalk | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # Start Netatalk servers. | ||||||
|  | atalk_startup() { | ||||||
|  | 	if [ x"$ATALKD_RUN" = x"yes" ]; then | ||||||
|  |  | ||||||
|  | 	# Try to load the AppleTalk kernel module if it was intended. | ||||||
|  |     if grep -q '^appletalk$' /etc/modules; then | ||||||
|  | 		/sbin/modprobe appletalk || echo "[could not load appletalk module]" | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  | 	# Start atalkd server. | ||||||
|  | 	/usr/local/sbin/atalkd | ||||||
|  |  | ||||||
|  | 	# register workstation | ||||||
|  | 	/usr/local/bin/nbprgstr -p 4 "$ATALK_NAME:Workstation$ATALK_ZONE" | ||||||
|  | 	/usr/local/bin/nbprgstr -p 4 "$ATALK_NAME:netatalk$ATALK_ZONE" | ||||||
|  |  | ||||||
|  | 	echo -n " atalkd" | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	# prepare startup of file services | ||||||
|  | 	if [ "x$CNID_METAD_RUN" = "xyes" -a -x /usr/local/sbin/cnid_metad ] ; then | ||||||
|  | 		echo -n " cnid_metad" | ||||||
|  |         /usr/local/sbin/cnid_metad $CNID_CONFIG | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  | 	if [ x"$AFPD_RUN" = x"yes" ]; then | ||||||
|  | 	/usr/local/sbin/afpd $AFPD_UAMLIST -g $AFPD_GUEST -c $AFPD_MAX_CLIENTS \ | ||||||
|  | 		-n "$ATALK_NAME$ATALK_ZONE" | ||||||
|  | 	echo -n " afpd" | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  |     if [ "x$ATALKD_RUN" = "xyes" ]; then | ||||||
|  |         if [ "x$PAPD_RUN" = "xyes" ]; then | ||||||
|  |             /usr/local/sbin/papd | ||||||
|  |             echo -n " papd" | ||||||
|  |         fi | ||||||
|  |  | ||||||
|  |         if [ x"$TIMELORD_RUN" = x"yes" ]; then | ||||||
|  |             /usr/local/sbin/timelord | ||||||
|  |             echo -n " timelord" | ||||||
|  |         fi | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  |  | ||||||
|  | case "$1" in | ||||||
|  | 	start) | ||||||
|  | 		if [ "x$ATALK_BGROUND" = "xyes" -a "x$ATALKD_RUN" = "xyes" ]; then | ||||||
|  | 			echo "Starting Netatalk services in the background." | ||||||
|  | 			atalk_startup >/dev/null & | ||||||
|  | 		else | ||||||
|  | 			echo -n "Starting Netatalk services (this will take a while): " | ||||||
|  | 			atalk_startup | ||||||
|  | 			echo "." | ||||||
|  | 		fi | ||||||
|  | 	;; | ||||||
|  |  | ||||||
|  | 	stop) | ||||||
|  | 		echo -n "Stopping Netatalk Daemons:" | ||||||
|  | 		echo -n " afpd" | ||||||
|  | 		start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/afpd | ||||||
|  |  | ||||||
|  | 		echo -n " cnid_metad" | ||||||
|  | 		start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/cnid_metad | ||||||
|  |  | ||||||
|  | 		if test -x /usr/local/sbin/papd; then | ||||||
|  |                     echo -n " papd" | ||||||
|  | 		    start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/papd | ||||||
|  | 	        fi | ||||||
|  |  | ||||||
|  | 		if test -x /usr/local/sbin/timelord; then | ||||||
|  |                     echo -n " timelord" | ||||||
|  | 		    start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/timelord | ||||||
|  | 	        fi | ||||||
|  |  | ||||||
|  | 		if test -x /usr/local/sbin/atalkd; then | ||||||
|  |                     echo -n " atalkd" | ||||||
|  | 		    start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/atalkd | ||||||
|  | 	        fi | ||||||
|  |  | ||||||
|  | 		echo "." | ||||||
|  | 	;; | ||||||
|  |  | ||||||
|  | 	restart) | ||||||
|  | 		$0 force-reload | ||||||
|  | 	;; | ||||||
|  |  | ||||||
|  | 	force-reload) | ||||||
|  | 		echo -n "Restarting Netatalk Daemons (this will take a while)" | ||||||
|  | 		$0 stop | ||||||
|  | 		echo -n "." | ||||||
|  | 		sleep 2 | ||||||
|  | 		echo -n "." | ||||||
|  | 		if $0 start; then | ||||||
|  | 			echo "done." | ||||||
|  | 		fi | ||||||
|  | 	;; | ||||||
|  |  | ||||||
|  | 	*) | ||||||
|  | 		echo "Usage: $0 {start|stop|restart|force-reload}" >&2 | ||||||
|  | 		exit 1 | ||||||
|  | 	;; | ||||||
|  | esac | ||||||
| @@ -78,7 +78,7 @@ if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then | |||||||
|                     if [[ $(sha1sum /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then |                     if [[ $(sha1sum /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then | ||||||
|                         echo "Removing defective AppleTalk module from kernel $kernelRelease..." |                         echo "Removing defective AppleTalk module from kernel $kernelRelease..." | ||||||
|                         sudo rm -rf /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null |                         sudo rm -rf /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null | ||||||
|                         wget -qO /tmp/appletalk.ko.gz appleii.ivanx.com/a2server/files/appletalk-$kernelRelease.ko.gz |                         wget -qO /tmp/appletalk.ko.gz ${A2SERVER_SCRIPT_URL}files/appletalk-$kernelRelease.ko.gz | ||||||
|                         if [[ $? -eq 0 ]]; then |                         if [[ $? -eq 0 ]]; then | ||||||
|                             # if we found a prebuilt one on a2server site, so install it |                             # if we found a prebuilt one on a2server site, so install it | ||||||
|                             gunzip -f /tmp/appletalk.ko.gz |                             gunzip -f /tmp/appletalk.ko.gz | ||||||
| @@ -3,18 +3,29 @@ | |||||||
|  |  | ||||||
| # --- Setting up the share volume | # --- Setting up the share volume | ||||||
|  |  | ||||||
|  | # 1.3.0: move /media/A2SHARED (pre-1.3.0) to /srv/A2SERVER | ||||||
|  | if [[ -d /media/A2SHARED ]]; then | ||||||
|  |     echo "A2SERVER: Moving /media/A2SHARED to /srv/A2SERVER..." | ||||||
|  |     sudo /etc/init.d/netatalk stop &> /dev/null | ||||||
|  |     sudo /etc/init.d/samba stop &> /dev/null | ||||||
|  |     [[ ! -d /srv ]] && sudo mkdir -p /srv | ||||||
|  |     sudo mv /media/A2SHARED /srv/A2SERVER | ||||||
|  |     sudo sed -i 's|/media/A2SHARED|/srv/A2SERVER|g' /usr/local/etc/netatalk/AppleVolumes.default | ||||||
|  |     [[ -f /etc/samba/smbd.conf ]] && sudo sed -i 's|/media/A2SHARED|/srv/A2SERVER|g' /etc/samba/smbd.conf | ||||||
|  |  | ||||||
|  | fi | ||||||
|  |  | ||||||
| # skip if we're already set up | # skip if we're already set up | ||||||
| if [[ -d /media/A2SHARED ]]; then | if [[ -d /srv/A2SERVER ]]; then | ||||||
|  |  | ||||||
|     echo "A2SERVER: Shared disk is already prepared for use." |     echo "A2SERVER: Shared volume is already prepared for use." | ||||||
|  |  | ||||||
| else | else | ||||||
|  |  | ||||||
|     echo "A2SERVER: Preparing the shared files disk..." |     echo "A2SERVER: Preparing the shared files volume..." | ||||||
|  |  | ||||||
|     sudo mkdir /media/A2SHARED |     sudo mkdir -p /srv/A2SERVER | ||||||
|  |  | ||||||
|     sudo chown $USER:$USER /media/A2SHARED |     sudo chown $USER:$USER /srv/A2SERVER | ||||||
|  |  | ||||||
| fi | fi | ||||||
|   | |||||||
| @@ -7,32 +7,63 @@ | |||||||
| # Ensure URL we'll use ends in a / | # Ensure URL we'll use ends in a / | ||||||
| case "$A2SERVER_SCRIPT_URL" in | case "$A2SERVER_SCRIPT_URL" in | ||||||
| 	*/) scriptURL="$A2SERVER_SCRIPT_URL" ;; | 	*/) scriptURL="$A2SERVER_SCRIPT_URL" ;; | ||||||
| 	*) scriptURL="${A2SERVER_SCRIPT_URL:-http://appleii.ivanx.com/a2server}/" ;; | 	*) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current}/" ;; | ||||||
| esac | esac | ||||||
|  | case "$A2SERVER_BINARY_URL" in | ||||||
|  | 	*/) binaryURL="$A2SERVER_BINARY_URL" ;; | ||||||
|  | 	*) binaryURL="${A2SERVER_BINARY_URL:-http://ivanx.com/a2server/files}/" ;; | ||||||
|  | esac | ||||||
|  | useExternalURL=1 | ||||||
|  | [[ $A2SERVER_NO_EXTERNAL ]] && useExternalURL= | ||||||
|  |  | ||||||
|  | debianVersion=$(cat /etc/debian_version 2> /dev/null) | ||||||
| isRpi= | isRpi= | ||||||
| [[ -f /usr/bin/raspi-config ]] && isRpi=1 | arch= | ||||||
|  | if [[ -f /usr/bin/raspi-config ]]; then | ||||||
|  |     isRpi=1 | ||||||
|  |     arch='rpi' | ||||||
|  | elif lsb_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ $(cut -d . -f 1 <<< $debianVersion) -ge "7" ]]; then | ||||||
|  |     uname_m="$(uname -m)" | ||||||
|  |     if [[ $uname_m == "i686" ]]; then | ||||||
|  |         arch='debian_x86' | ||||||
|  |     elif [[ $uname_m == "x86_64" ]]; then | ||||||
|  |         arch='debian_x64' | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
| isDebian= | debianName= | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1 < /etc/debian_version) -ge "7" ) && ( $(uname -m) == "i686" ) ]] && isDebian=1 | if [[ $debianVersion ]]; then | ||||||
|  |     debianMajor=$(cut -d . -f 1 <<< $debianVersion) | ||||||
| isJessie= |     if [[ $debianMajor == "8" ]]; then | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1-2 < /etc/debian_version) == "8." ) ]] && isJessie=1 |         debianName="jessie" | ||||||
|  |     elif [[ $debianMajor == "7" ]]; then | ||||||
|  |         debianName="wheezy" | ||||||
|  |     else | ||||||
|  |         debianName="unknown" | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
| echo "A2SERVER: Installing A2SERVER tools..." | echo "A2SERVER: Installing A2SERVER tools..." | ||||||
|  |  | ||||||
| if ! command -v nulib2 > /dev/null; then | # delete older nulib2 which doesn't correctly handle zero-length forks in GSHK-created archives | ||||||
|  | if hash nulib2 &> /dev/null; then | ||||||
|  |     nulib2version=$(nulib2 | sed -n 2p | sed 's|^.*v\([0-9]\)\.\([0-9]\)\.\([0-9]\).*$|\1\2\3|' 2> /dev/null) | ||||||
|  |     if (( $nulib2version < 310 )); then | ||||||
|  |         sudo apt-get -y purge nulib2 &> /dev/null | ||||||
|  |         sudo rm $(command -v nulib2) &> /dev/null | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | if ! hash nulib2 &> /dev/null; then | ||||||
|  |  | ||||||
|     echo "A2SERVER: Installing nulib2..." |     echo "A2SERVER: Installing nulib2..." | ||||||
|  |  | ||||||
|     cd /tmp |     cd /tmp | ||||||
|     if [[ $isRpi ]]; then |     if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then | ||||||
|         wget -qO- "http://appleii.ivanx.com/a2server/files/nulib2-rpi.tgz" | sudo tar Pzx |         { wget -qO- "${binaryURL}precompiled/nulib2-3.1.0a2-${arch}.tgz" | sudo tar Pzx; } &> /dev/null | ||||||
|     elif [[ $isDebian ]]; then |  | ||||||
|         wget -qO- "http://appleii.ivanx.com/a2server/files/nulib2-debian7_x86.tgz" | sudo tar Pzx |  | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     if ! command -v nulib2 > /dev/null; then |     if ! hash nulib2 &> /dev/null; then | ||||||
|  |  | ||||||
|         if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then |         if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then | ||||||
|             # prepare for installing packages |             # prepare for installing packages | ||||||
| @@ -40,25 +71,35 @@ if ! command -v nulib2 > /dev/null; then | |||||||
|             touch /tmp/a2server-packageReposUpdated |             touch /tmp/a2server-packageReposUpdated | ||||||
|         fi |         fi | ||||||
|  |  | ||||||
|         sudo apt-get -y install build-essential |         # Dependencies: build-dep for nulib | ||||||
|         sudo apt-get -y install zlib1g-dev |         sudo apt-get -y install build-essential zlib1g-dev | ||||||
|         sudo apt-get -y clean |         sudo apt-get -y clean | ||||||
|  |  | ||||||
|         cd /tmp |         cd /tmp | ||||||
|         rm -rf /tmp/nulib &> /dev/null |         rm -rf /tmp/nulib2 &> /dev/null | ||||||
|         mkdir /tmp/nulib |         mkdir /tmp/nulib2 | ||||||
|         cd /tmp/nulib |         cd /tmp/nulib2 | ||||||
|         wget -q -O nulib.tgz http://web.archive.org/web/20131031160750/http://www.nulib.com/downloads/nulibdist.tar.gz |         if [[ $useExternalURL ]]; then | ||||||
|         tar zxf nulib.tgz |             wget -q -O nulib2-3.1.0a2.zip "https://github.com/fadden/nulib2/archive/20fe7efb4d37fedf807416c16d74d51d893ea48a.zip" | ||||||
|         cd nufxlib* |             unzip nulib2-3.1.0a2.zip 2> /dev/null | ||||||
|  |             rm nulib2-3.1.0a2.zip &> /dev/null | ||||||
|  |         fi | ||||||
|  |         if [ ! -d nulib2* ]; then | ||||||
|  |             wget -q -O nulib2-3.1.0a2.zip "${binaryURL}external/source/nulib2-3.1.0a2.zip" | ||||||
|  |             unzip nulib2-3.1.0a2.zip 2> /dev/null | ||||||
|  |             rm nulib2-3.1.0a2.zip &> /dev/null | ||||||
|  |         fi | ||||||
|  |         cd nulib2* | ||||||
|  |         cd nufxlib | ||||||
|         ./configure |         ./configure | ||||||
|         make |         make | ||||||
|         sudo make install |         sudo make install | ||||||
|         cd ../nulib2* |         cd ../nulib2 | ||||||
|         ./configure |         ./configure | ||||||
|         make |         make | ||||||
|         sudo make install |         sudo make install | ||||||
|         cd |         cd | ||||||
|         rm -rf /tmp/nulib |         rm -rf /tmp/nulib2 | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
| else | else | ||||||
| @@ -68,7 +109,7 @@ fi | |||||||
| # download and install The Unarchiver, for expanding Apple disk images | # download and install The Unarchiver, for expanding Apple disk images | ||||||
| # http://wakaba.c3.cx/s/apps/unarchiver.html | # http://wakaba.c3.cx/s/apps/unarchiver.html | ||||||
|  |  | ||||||
| if ! command -v unar > /dev/null; then | if ! hash unar &> /dev/null; then | ||||||
|  |  | ||||||
|     echo "A2SERVER: Installing The Unarchiver..." |     echo "A2SERVER: Installing The Unarchiver..." | ||||||
|  |  | ||||||
| @@ -78,34 +119,39 @@ if ! command -v unar > /dev/null; then | |||||||
|         touch /tmp/a2server-packageReposUpdated |         touch /tmp/a2server-packageReposUpdated | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     if [[ $isJessie ]]; then |     # jessie and later: Just use the unar package | ||||||
|         sudo apt-get install -y unar |     if [[ $debianMajor -ge 8 ]]; then | ||||||
|  |         sudo apt-get -y install unar | ||||||
|         sudo apt-get clean |         sudo apt-get clean | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     if ! command -v unar > /dev/null; then |     if ! hash unar &> /dev/null; then | ||||||
|         if [[ $isRpi || $isDebian ]]; then |         if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then | ||||||
|  |             # Dependencies: for unar | ||||||
|             sudo apt-get -y install libgnustep-base1.22 |             sudo apt-get -y install libgnustep-base1.22 | ||||||
|             sudo apt-get clean |             sudo apt-get clean | ||||||
|             if [[ $isRpi ]]; then |             { wget -qO- "${binaryURL}precompiled/unar-${arch}_${debianName}.tgz" | sudo tar Pzx; } &> /dev/null | ||||||
|                 wget -qO- "http://appleii.ivanx.com/a2server/files/unar-rpi_wheezy.tgz" | sudo tar Pzx |  | ||||||
|             elif [[ $isDebian ]]; then |  | ||||||
|                 wget -qO- "http://appleii.ivanx.com/a2server/files/unar-debian7_x86.tgz" | sudo tar Pzx |  | ||||||
|             fi |  | ||||||
|         fi |         fi | ||||||
|  |  | ||||||
|         # If all else fails, compile from source. |         # If all else fails, compile from source. | ||||||
|         if ! command -v unar >/dev/null; then |         if ! hash unar &> /dev/null; then | ||||||
|             sudo apt-get -y install build-essential |  | ||||||
|             sudo apt-get -y install libgnustep-base-dev libz-dev libbz2-dev |             # Dependencies: build-deps for unar | ||||||
|             sudo apt-get -y install libssl-dev libicu-dev unzip |             sudo apt-get -y install build-essential libgnustep-base-dev libz-dev libbz2-dev libssl-dev libicu-dev unzip | ||||||
|             sudo apt-get clean |             sudo apt-get clean | ||||||
|  |  | ||||||
|             rm -rf /tmp/unar &> /dev/null |             rm -rf /tmp/unar &> /dev/null | ||||||
|             mkdir /tmp/unar |             mkdir /tmp/unar | ||||||
|             cd /tmp/unar |             cd /tmp/unar | ||||||
|             wget -qO unar1.7_src.zip http://theunarchiver.googlecode.com/files/unar1.7_src.zip |             if [[ $useExternalURL ]]; then | ||||||
|             unzip -o unar1.7_src.zip |                 wget -O unar-1.8.1.zip https://github.com/incbee/Unarchiver/archive/unar-1.8.1.zip | ||||||
|             cd The\ Unarchiver/XADMaster |                 unzip -o unar-1.8.1.zip &> /dev/null | ||||||
|  |             fi | ||||||
|  |             if [ ! -d *Unarchiver*/XADMaster ]; then # need single bracket for glob | ||||||
|  |                 wget -O unar-1.8.1.zip ${binaryURL}external/source/unar-1.8.1.zip | ||||||
|  |                 unzip -o unar-1.8.1.zip &> /dev/null | ||||||
|  |             fi | ||||||
|  |             cd *Unarchiver*/XADMaster | ||||||
|             make -f Makefile.linux |             make -f Makefile.linux | ||||||
|             sudo mv lsar unar /usr/local/bin |             sudo mv lsar unar /usr/local/bin | ||||||
|             cd ../Extra |             cd ../Extra | ||||||
| @@ -119,9 +165,17 @@ else | |||||||
|     echo "A2SERVER: The Unarchiver has already been installed." |     echo "A2SERVER: The Unarchiver has already been installed." | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if ! command -v unzip >/dev/null; then | if ! hash unzip &> /dev/null; then | ||||||
|     echo "A2SERVER: Installing unzip..." |     echo "A2SERVER: Installing unzip..." | ||||||
|  |     if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then | ||||||
|  |         # prepare for installing packages | ||||||
|  |         sudo apt-get -y update | ||||||
|  |         touch /tmp/a2server-packageReposUpdated | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  |     # Dependencies: unzip | ||||||
|     sudo apt-get -y install unzip |     sudo apt-get -y install unzip | ||||||
|  |     sudo apt-get clean | ||||||
| else | else | ||||||
|     echo "A2SERVER: unzip has already been installed." |     echo "A2SERVER: unzip has already been installed." | ||||||
| fi | fi | ||||||
| @@ -138,9 +192,14 @@ sudo wget -q -O /usr/local/bin/cppo "${scriptURL}scripts/tools/cppo.txt" | |||||||
| sudo chmod ugo+x /usr/local/bin/cppo | sudo chmod ugo+x /usr/local/bin/cppo | ||||||
| sudo wget -q -O /usr/local/etc/a2server-help.txt "${scriptURL}scripts/tools/a2server-help.txt" | sudo wget -q -O /usr/local/etc/a2server-help.txt "${scriptURL}scripts/tools/a2server-help.txt" | ||||||
| sudo wget -q -O /usr/local/etc/a2server-aliases "${scriptURL}scripts/tools/a2server-aliases.txt" | sudo wget -q -O /usr/local/etc/a2server-aliases "${scriptURL}scripts/tools/a2server-aliases.txt" | ||||||
|  | sudo wget -q -O /usr/local/etc/a2serverrc "${scriptURL}scripts/tools/a2serverrc.txt" | ||||||
|  |  | ||||||
| grep a2server-aliases /etc/bash.bashrc > /dev/null || \ | # 1.3.0: a2serverrc is now called from /etc/bash.bashrc, | ||||||
| echo "source /usr/local/etc/a2server-aliases" | sudo tee -a /etc/bash.bashrc > /dev/null | #   which in turn calls a2server-aliases | ||||||
|  | grep 'a2server-aliases' /etc/bash.bashrc > /dev/null && \ | ||||||
|  | sudo sed -i 's/a2server-aliases/a2serverrc/' /etc/bash.bashrc | ||||||
|  | grep 'a2serverrc' /etc/bash.bashrc > /dev/null || \ | ||||||
|  | echo "source /usr/local/etc/a2serverrc" | sudo tee -a /etc/bash.bashrc > /dev/null | ||||||
|  |  | ||||||
| motd="/etc/motd" | motd="/etc/motd" | ||||||
| if [[ ! $(grep A2SERVER $motd) ]]; then | if [[ ! $(grep A2SERVER $motd) ]]; then | ||||||
|   | |||||||
| @@ -17,20 +17,44 @@ | |||||||
| # Ensure URL we'll use ends in a / | # Ensure URL we'll use ends in a / | ||||||
| case "$A2SERVER_SCRIPT_URL" in | case "$A2SERVER_SCRIPT_URL" in | ||||||
| 	*/) scriptURL="$A2SERVER_SCRIPT_URL" ;; | 	*/) scriptURL="$A2SERVER_SCRIPT_URL" ;; | ||||||
| 	*) scriptURL="${A2SERVER_SCRIPT_URL:-http://appleii.ivanx.com/a2server}/" ;; | 	*) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current}/" ;; | ||||||
| esac | esac | ||||||
|  | case "$A2SERVER_BINARY_URL" in | ||||||
|  | 	*/) binaryURL="$A2SERVER_BINARY_URL" ;; | ||||||
|  | 	*) binaryURL="${A2SERVER_BINARY_URL:-http://ivanx.com/a2server/files}/" ;; | ||||||
|  | esac | ||||||
|  | useExternalURL=1 | ||||||
|  | [[ $A2SERVER_NO_EXTERNAL ]] && useExternalURL= | ||||||
|  |  | ||||||
|  | debianVersion=$(cat /etc/debian_version 2> /dev/null) | ||||||
| isRpi= | isRpi= | ||||||
| [[ -f /usr/bin/raspi-config ]] && isRpi=1 | arch= | ||||||
|  | if [[ -f /usr/bin/raspi-config ]]; then | ||||||
|  |     isRpi=1 | ||||||
|  |     arch='rpi' | ||||||
|  | elif lsb_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ $(cut -d . -f 1 <<< $debianVersion) -ge "7" ]]; then | ||||||
|  |     uname_m="$(uname -m)" | ||||||
|  |     if [[ $uname_m == "i686" ]]; then | ||||||
|  |         arch='debian_x86' | ||||||
|  |     elif [[ $uname_m == "x86_64" ]]; then | ||||||
|  |         arch='debian_x64' | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
| isDebian_x86= | debianName= | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1 < /etc/debian_version) -ge 7 ) && ( $(uname -m) == "i686" ) ]] && isDebian_x86=1 | if [[ $debianVersion ]]; then | ||||||
|  |     debianMajor=$(cut -d . -f 1 <<< $debianVersion) | ||||||
| isJessie= |     if [[ $debianMajor == "8" ]]; then | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1-2 < /etc/debian_version) == "8." ) ]] && isJessie=1 |         debianName="jessie" | ||||||
|  |     elif [[ $debianMajor == "7" ]]; then | ||||||
|  |         debianName="wheezy" | ||||||
|  |     else | ||||||
|  |         debianName="unknown" | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
| # skip this if already done | # skip this if already done | ||||||
| if [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(cat /usr/local/etc/A2SERVER-version) >= 101 )); then | if [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) >= 101 )); then | ||||||
|  |  | ||||||
|     echo "A2SERVER: Netatalk is already installed." |     echo "A2SERVER: Netatalk is already installed." | ||||||
|  |  | ||||||
| @@ -38,8 +62,11 @@ else | |||||||
|  |  | ||||||
|     echo "A2SERVER: Installing Netatalk (this will take a while)..." |     echo "A2SERVER: Installing Netatalk (this will take a while)..." | ||||||
|  |  | ||||||
|     # stop Netatalk if running (during upgrade) |     # stop Netatalk and samba if running (during upgrade) | ||||||
|     [[ $(ps --no-headers -C afpd) ]] && sudo /etc/init.d/netatalk stop |     if [[ $(ps --no-headers -C afpd) ]]; then | ||||||
|  |         sudo /etc/init.d/netatalk stop &> /dev/null | ||||||
|  |         sudo /etc/init.d/samba stop &> /dev/null | ||||||
|  |     fi | ||||||
|  |  | ||||||
|     if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then |     if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then | ||||||
|         # prepare for installing packages |         # prepare for installing packages | ||||||
| @@ -47,61 +74,58 @@ else | |||||||
|         touch /tmp/a2server-packageReposUpdated |         touch /tmp/a2server-packageReposUpdated | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|  |     # not being used as of 1.2.9, but it's available if full URL to .deb package is supplied | ||||||
|     getOldPackage () { |     getOldPackage () { | ||||||
|         for url in $@; do |         for url in $@; do | ||||||
|             pkgFile=${url##*/} |             pkgFile=${url##*/} | ||||||
|             pkgName=${pkgFile%%_*} |             pkgName=${pkgFile%%_*} | ||||||
|             if ! dpkg -l $pkgName 2> /dev/null | grep -q '^ii'; then |             if ! dpkg -l $pkgName 2> /dev/null | grep -q '^ii'; then | ||||||
|                 wget -qO /tmp/${url##*/} "$url" |                 if [[ $useExternalURL ]]; then | ||||||
|                 sudo dpkg -i /tmp/${url##*/} |                     wget -qO "/tmp/${url##*/}" "$url" | ||||||
|  |                 fi | ||||||
|  |                 if [[ $? -ne 0 || ! -f "/tmp/${url##*/}" ]]; then | ||||||
|  |                     wget -qO "/tmp/${url##*/}" "${binaryURL}external/deb/${url##*/}" | ||||||
|  |                 fi | ||||||
|  |                 sudo dpkg -i "/tmp/${url##*/}" | ||||||
|                 sudo apt-get clean |                 sudo apt-get clean | ||||||
|                 rm /tmp/${url##*/} |                 rm "/tmp/${url##*/}" | ||||||
|             fi |             fi | ||||||
|         done |         done | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     compileFromSource=1 |     compileFromSource=1 | ||||||
|     urls= |     urls= | ||||||
|     while [[ $isRpi || $isDebian_x86 ]]; do |     while [[ $arch ]]; do | ||||||
|         # Install runtime libraries needed by Netatalk |         # Install runtime libraries needed by Netatalk | ||||||
|         if [[ $isJessie ]]; then |         if [[ $(apt-cache search '^libdb5.1$') ]]; then # Wheezy | ||||||
|             if [[ $isRpi ]]; then |             # Dependencies: netatalk 2.2.4 | ||||||
|                 getOldPackage "http://mirrordirector.raspbian.org/raspbian/pool/main/d/db/libdb5.1_5.1.29-5_armhf.deb" |  | ||||||
|             elif [[ $isDebian_x86 ]]; then |  | ||||||
|                 getOldPackage "http://ftp.debian.org/debian/pool/main/d/db/libdb5.1_5.1.29-5_i386.deb" |  | ||||||
|             fi |  | ||||||
|         elif [[ $(apt-cache search '^libdb4.8$') ]]; then |  | ||||||
|             sudo apt-get -y install libdb4.8 |  | ||||||
|         elif [[ $(apt-cache search '^libdb5.1$') ]]; then |  | ||||||
|             sudo apt-get -y install libdb5.1 |             sudo apt-get -y install libdb5.1 | ||||||
|  |         elif [[ $(apt-cache search '^libdb5.3$') ]]; then # Jessie | ||||||
|  |             # Dependencies: netatalk 2.2.4 | ||||||
|  |             sudo apt-get -y install libdb5.3 | ||||||
|         else |         else | ||||||
|             break |             break | ||||||
|         fi |         fi | ||||||
|         if [[ $(apt-cache search '^libssl1.0.0$') ]]; then |         if [[ $(apt-cache search '^libssl1.0.0$') ]]; then | ||||||
|  |             # Dependencies: netatalk 2.2.4 | ||||||
|             sudo apt-get -y install libssl1.0.0 |             sudo apt-get -y install libssl1.0.0 | ||||||
|         elif [[ $(apt-cache search '^libssl0.9.8$') ]]; then |  | ||||||
|             sudo apt-get -y install libssl0.9.8 |  | ||||||
|         else |         else | ||||||
|             break |             break | ||||||
|         fi |         fi | ||||||
|  |  | ||||||
|         if [[ $isJessie ]]; then |         if [[ $(apt-cache search '^libgcrypt11$') ]]; then # Wheezy | ||||||
|             if [[ $isRpi ]]; then |             # Dependencies: netatalk 2.2.4 | ||||||
|                 getOldPackage "http://mirrordirector.raspbian.org/raspbian/pool/main/libg/libgcrypt11/libgcrypt11_1.5.0-5+deb7u3_armhf.deb" |  | ||||||
|             elif [[ $isDebian_x86 ]]; then |  | ||||||
|                 getOldPackage "http://ftp.debian.org/debian/pool/main/libg/libgcrypt11/libgcrypt11_1.5.0-5+deb7u3_i386.deb" |  | ||||||
|             fi |  | ||||||
|         elif [[ $(apt-cache search '^libgcrypt11$') ]]; then |  | ||||||
|             sudo apt-get -y install libgcrypt11 |             sudo apt-get -y install libgcrypt11 | ||||||
|  |         elif [[ $(apt-cache search '^libgcrypt20$') ]]; then # Jessie | ||||||
|  |             # Dependencies: netatalk 2.2.4 | ||||||
|  |             sudo apt-get -y install libgcrypt20 | ||||||
|         else |         else | ||||||
|             break |             break | ||||||
|         fi |         fi | ||||||
|  |  | ||||||
|         # install Netatalk |         # install Netatalk | ||||||
|         if [[ $isRpi ]]; then |         if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then | ||||||
|             { wget -qO- /tmp/netatalk.tgz "http://appleii.ivanx.com/a2server/files/netatalk224-rpi_wheezy.tgz" | sudo tar Pzx; } 2> /dev/null |             { wget -qO- "${binaryURL}precompiled/netatalk224-${arch}_${debianName}.tgz" | sudo tar Pzx; } &> /dev/null | ||||||
|         elif [[ $isDebian_x86 ]]; then |  | ||||||
|             { wget -qO- /tmp/netatalk.tgz "http://appleii.ivanx.com/a2server/files/netatalk224-debian7_x86.tgz" | sudo tar Pzx; } 2> /dev/null |  | ||||||
|         fi |         fi | ||||||
|         sudo mandb &> /dev/null |         sudo mandb &> /dev/null | ||||||
|  |  | ||||||
| @@ -111,34 +135,25 @@ else | |||||||
|     done |     done | ||||||
|  |  | ||||||
|     if [[ $compileFromSource ]]; then |     if [[ $compileFromSource ]]; then | ||||||
|         # Install development libraries needed by Netatalk |         # Dependencies: build-deps for netatalk 2.2.4 | ||||||
|         sudo apt-get -y install build-essential |         sudo apt-get -y install build-essential libssl-dev | ||||||
|         sudo apt-get -y install libssl-dev |         if [[ $(apt-cache search '^libdb5.1-dev$') ]]; then # Wheezy | ||||||
|         if [[ $isJessie ]]; then |             # Dependencies: build-deps for netatalk 2.2.4 | ||||||
|             if [[ $isRpi ]]; then |  | ||||||
|                 getOldPackage "http://mirrordirector.raspbian.org/raspbian/pool/main/d/db/libdb5.1-dev_5.1.29-5_armhf.deb" |  | ||||||
|             elif [[ $isDebian_x86 ]]; then |  | ||||||
|                 getOldPackage "http://ftp.us.debian.org/debian/pool/main/d/db/libdb5.1-dev_5.1.29-5_i386.deb" |  | ||||||
|             fi |  | ||||||
|         elif [[ $(apt-cache search '^libdb4.8-dev$') ]]; then |  | ||||||
|             sudo apt-get -y install libdb4.8-dev |  | ||||||
|         elif [[ $(apt-cache search '^libdb5.1-dev$') ]]; then |  | ||||||
|             sudo apt-get -y install libdb5.1-dev |             sudo apt-get -y install libdb5.1-dev | ||||||
|  |         elif [[ $(apt-cache search '^libdb5.3-dev$') ]]; then # Jessie | ||||||
|  |             # Dependencies: build-deps for netatalk 2.2.4 | ||||||
|  |             sudo apt-get -y install libdb5.3-dev | ||||||
|         else |         else | ||||||
|             echo "A2SERVER: WARNING: unknown version of libdb-dev is being installed" |             echo "A2SERVER: WARNING: unknown version of libdb-dev is being installed." | ||||||
|  |             # Dependencies: build-deps for netatalk 2.2.4 | ||||||
|             sudo apt-get -y install libdb-dev |             sudo apt-get -y install libdb-dev | ||||||
|         fi |         fi | ||||||
|         if [[ $isJessie ]]; then |         if [[ $(apt-cache search '^libgcrypt11-dev$') ]]; then # Jessie or Wheezy | ||||||
|             sudo apt-get -y install libgpg-error-dev |             # Dependencies: build-deps for netatalk 2.2.4 | ||||||
|             if [[ $isRpi ]]; then |  | ||||||
|                 getOldPackage "http://mirrordirector.raspbian.org/raspbian/pool/main/libg/libgcrypt11/libgcrypt11-dev_1.5.0-5+deb7u3_armhf.deb" |  | ||||||
|             elif [[ $isDebian_x86 ]]; then |  | ||||||
|                 getOldPackage "http://ftp.debian.org/debian/pool/main/libg/libgcrypt11/libgcrypt11-dev_1.5.0-5+deb7u3_i386.deb" |  | ||||||
|             fi |  | ||||||
|         elif [[ $(apt-cache search '^libgcrypt11-dev$') ]]; then |  | ||||||
|             sudo apt-get -y install libgcrypt11-dev |             sudo apt-get -y install libgcrypt11-dev | ||||||
|         else |         else | ||||||
|             echo "A2SERVER: WARNING: unknown version of libgcrypt-dev is being installed" |             echo "A2SERVER: WARNING: unknown version of libgcrypt-dev is being installed." | ||||||
|  |             # Dependencies: build-deps for netatalk 2.2.4 | ||||||
|             sudo apt-get -y install $(apt-cache search '^libgcrypt.*dev$' | sort -r | head -1 | cut -d ' ' -f 1) |             sudo apt-get -y install $(apt-cache search '^libgcrypt.*dev$' | sort -r | head -1 | cut -d ' ' -f 1) | ||||||
|         fi |         fi | ||||||
|         sudo apt-get clean |         sudo apt-get clean | ||||||
| @@ -148,8 +163,14 @@ else | |||||||
|         mkdir /tmp/netatalk |         mkdir /tmp/netatalk | ||||||
|         cd /tmp/netatalk |         cd /tmp/netatalk | ||||||
|  |  | ||||||
|         wget -q "http://downloads.sourceforge.net/project/netatalk/netatalk/2.2.4/netatalk-2.2.4.tar.gz" |         if [[ $useExternalURL ]]; then | ||||||
|         tar zxf netatalk-2.2.4.tar.gz |             wget -qO netatalk-2.2.4.tar.gz "http://downloads.sourceforge.net/project/netatalk/netatalk/2.2.4/netatalk-2.2.4.tar.gz" | ||||||
|  |             tar zxf netatalk-2.2.4.tar.gz &> /dev/null | ||||||
|  |         fi | ||||||
|  |         if [[ ! -d netatalk-2.2.4 ]]; then | ||||||
|  |             wget -O netatalk-2.2.4.tar.gz "${binaryURL}external/source/netatalk-2.2.4.tar.gz" | ||||||
|  |             tar zxf netatalk-2.2.4.tar.gz &> /dev/null | ||||||
|  |         fi | ||||||
|         cd netatalk-2.2.4 |         cd netatalk-2.2.4 | ||||||
|  |  | ||||||
|         # Patch the source so file dates are preserved during a GS/OS folder copy, |         # Patch the source so file dates are preserved during a GS/OS folder copy, | ||||||
| @@ -175,6 +196,40 @@ else | |||||||
|     fi |     fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | # --- Install MacIPgw | ||||||
|  | if ! hash macipgw &> /dev/null; then | ||||||
|  |     echo "A2SERVER: Installing TCP over AppleTalk (MacIP)..." | ||||||
|  |  | ||||||
|  |     if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then | ||||||
|  |         { wget -qO- "${binaryURL}precompiled/macipgw-${arch}.tgz" | sudo tar Pzx; } 2> /dev/null | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  |     if ! hash macipgw &> /dev/null; then | ||||||
|  |         wd="$PWD" | ||||||
|  |         sudo apt-get -y install build-essential | ||||||
|  |         rm -rf /tmp/macipgw &> /dev/null | ||||||
|  |         mkdir /tmp/macipgw | ||||||
|  |         cd /tmp/macipgw | ||||||
|  |         if [[ $useExternalURL ]]; then | ||||||
|  |             wget -qO macipgw.zip "https://github.com/zero2sixd/macipgw/archive/2a5f6a7521a627e46b18468d44f4306fb0a7b7ab.zip" | ||||||
|  |             unzip macipgw.zip 2> /dev/null | ||||||
|  |             rm macipgw.zip &> /dev/null | ||||||
|  |         fi | ||||||
|  |         if [[ ! -d macipgw-master ]]; then | ||||||
|  |             wget -qO macipgw.zip "${binaryURL}external/source/macipgw.zip" | ||||||
|  |             unzip macipgw.zip 2> /dev/null | ||||||
|  |             rm macipgw.zip &> /dev/null | ||||||
|  |         fi | ||||||
|  |         cd macipgw* | ||||||
|  |         make | ||||||
|  |         sudo make install | ||||||
|  |         cd "$wd" | ||||||
|  |         rm -rf /tmp/macipgw | ||||||
|  |     fi | ||||||
|  | else | ||||||
|  |     echo "A2SERVER: TCP over AppleTalk (MacIP) has already been installed." | ||||||
|  | fi | ||||||
|  |  | ||||||
| # --- Configuring Netatalk | # --- Configuring Netatalk | ||||||
|  |  | ||||||
| echo "A2SERVER: Configuring Netatalk..." | echo "A2SERVER: Configuring Netatalk..." | ||||||
| @@ -182,7 +237,7 @@ echo "A2SERVER: Configuring Netatalk..." | |||||||
| # if missing Netatalk startup file, download a fresh one | # if missing Netatalk startup file, download a fresh one | ||||||
| if [ ! -f /etc/init.d/netatalk ]; then | if [ ! -f /etc/init.d/netatalk ]; then | ||||||
|     echo "A2SERVER: Downloading new Netatalk startup script..." |     echo "A2SERVER: Downloading new Netatalk startup script..." | ||||||
|     sudo wget -qO /etc/init.d/netatalk http://appleii.ivanx.com/a2server/files/netatalk-init.d-clean.txt |     sudo wget -qO /etc/init.d/netatalk ${binaryURL}netatalk-init.d-clean.txt | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # make the Netatalk startup script work correctly | # make the Netatalk startup script work correctly | ||||||
| @@ -192,7 +247,16 @@ sudo sed -i 's/bin\/sh/bin\/bash/' /etc/init.d/netatalk | |||||||
| sudo sed -i 's/#ATALKD_RUN=no/ATALKD_RUN=yes/' /etc/default/netatalk | sudo sed -i 's/#ATALKD_RUN=no/ATALKD_RUN=yes/' /etc/default/netatalk | ||||||
| sudo sed -i 's/#ATALK_BGROUND=no/ATALK_BGROUND=yes/' /etc/default/netatalk | sudo sed -i 's/#ATALK_BGROUND=no/ATALK_BGROUND=yes/' /etc/default/netatalk | ||||||
| if [[ ! $(grep 'kernelRelease' /etc/init.d/netatalk) ]]; then | if [[ ! $(grep 'kernelRelease' /etc/init.d/netatalk) ]]; then | ||||||
|     sudo sed -i 's@\(\tif \[ x\"$ATALKD_RUN\)@\n\t# check for valid AppleTalk kernel module\n\t[[ $ATALKD_RUN == "yes" ]] \&\& { kernelRelease=$(uname -r); kernelMajorRelease=$(cut -d "." -f 1  <<< $kernelRelease); kernelMinorRelease=$(cut -d "." -f 2  <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); kernelPatchRelease=$(cut -d "." -f 3- <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); [[ ( $kernelMajorRelease -eq 3 \&\& $kernelMinorRelease -ge 12 \&\& $kernelMinorRelease -le 15 ) \&\& ( ! ( -f /usr/bin/raspi-config \&\& $kernelMinorRelease -eq 12 \&\& $kernelPatchRelease -ge 25 ) ) \&\& ( ( ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ) || $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d " ") != "ecb239fc084c36de93f6926e7749b80f6024f269" ) ]] \&\& { ATALKD_RUN=no; echo "[AppleTalk networking is not available.]" 1>\&2; } }\n\n\1@' /etc/init.d/netatalk |     sudo sed -i 's@\(\tif \[ x\"$ATALKD_RUN\)@\n\t# check for valid AppleTalk kernel module\n\t[[ $ATALKD_RUN == "yes" ]] \&\& { kernelRelease=$(uname -r); kernelMajor=$(cut -d "." -f 1  <<< $kernelRelease); kernelMinor=$(cut -d "." -f 2  <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); kernelPatch=$(cut -d "." -f 3- <<< $kernelRelease | sed '"'"'s/\\(^[0-9]*\\)[^0-9].*$/\\1/'"'"'); [[ ( $kernelMajor -eq 3 \&\& $kernelMinor -ge 12 \&\& $kernelMinor -le 15 ) \&\& ( ! ( -f /usr/bin/raspi-config \&\& $kernelMinor -eq 12 \&\& $kernelPatch -ge 25 ) ) \&\& ( ( ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ) || $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d " ") != "ecb239fc084c36de93f6926e7749b80f6024f269" ) ]] \&\& { ATALKD_RUN=no; echo "[AppleTalk networking is not available.]" 1>\&2; } }\n\n\1@' /etc/init.d/netatalk | ||||||
|  | fi | ||||||
|  | sudo sed -i 's/Starting Netatalk services (this will take a while): /Starting Netatalk services"\n\t\t\t[[ $ATALKD_RUN == "yes" ]] \&\& echo -n " (this will take 45 seconds)"\n\t\t\techo -n ":/' /etc/init.d/netatalk | ||||||
|  | sudo sed -i 's/Starting Netatalk services in the background./Netatalk services will be available in 45 seconds./' /etc/init.d/netatalk | ||||||
|  | sudo sed -i 's/-n "Restarting Netatalk Daemons (this will take a while)"/"Restarting Netatalk Daemons."/' /etc/init.d/netatalk | ||||||
|  |  | ||||||
|  | # enable MacIPgw support after launching atalkd | ||||||
|  | if ! grep -q -i 'macipgw' /etc/init.d/netatalk; then | ||||||
|  |     sudo sed -i ':a;N;$!ba;s@\(echo -n " atalkd"\)\(.*# prepare\)@\1\n\n\t\t# start MacIPgw (TCP over AppleTalk) service\n\t\tps aux | grep -q "[m]acipgw" \&\& sudo killall macipgw 2> /dev/null || :\n\t\tatalkd_interface=$(grep "^[^ #]" /etc/netatalk/atalkd.conf | tail -1 | cut -d " " -f 1)\n\t\tsysctl -w net.ipv4.ip_forward=1 > /dev/null\n\t\tmacipgw -n 8.8.8.8 192.168.151.0 255.255.255.0\n\t\t/sbin/iptables -t nat -A POSTROUTING -o ${atalkd_interface} -j MASQUERADE\n\t\t/sbin/iptables -A FORWARD -i ${atalkd_interface} -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT\n\t\t/sbin/iptables -A FORWARD -i tun1 -o ${atalkd_interface} -j ACCEPT\n\n\t\techo -n " macipgw"\n\2@' /etc/init.d/netatalk | ||||||
|  |     sudo sed -i 's@\(start-stop-daemon --stop --quiet --oknodo --exec /usr/local/sbin/atalkd.*$\)@\1\n                    echo -n " macipgw"\n            sudo killall macipgw 2> /dev/null@' /etc/init.d/netatalk | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # enable network boot support in netatalk | # enable network boot support in netatalk | ||||||
| @@ -231,12 +295,12 @@ sudo sed -i 's/^~/#share1\n\n#share2/' \ | |||||||
| sudo sed -i 's/^:DEFAULT/#:DEFAULT/' \ | sudo sed -i 's/^:DEFAULT/#:DEFAULT/' \ | ||||||
| /usr/local/etc/netatalk/AppleVolumes.default | /usr/local/etc/netatalk/AppleVolumes.default | ||||||
|  |  | ||||||
| if [[ ! $(grep ^eth0 /usr/local/etc/netatalk/atalkd.conf) && ! $(grep ^wlan0 /usr/local/etc/netatalk/atalkd.conf) ]]; then | # if [[ ! $(grep ^eth0 /usr/local/etc/netatalk/atalkd.conf) && ! $(grep ^wlan0 /usr/local/etc/netatalk/atalkd.conf) ]]; then | ||||||
|  | if [[ $(tac /usr/local/etc/netatalk/atalkd.conf | sed '/./,$!d' | head -1 | cut -c 1) == "#" ]]; then | ||||||
|     # enable netatalk on the default network interface |     # enable netatalk on the default network interface | ||||||
|     # needs -router and -zone to prevent GS/OS AppleShare CDEV crash when used |     # needs -router and -zone to prevent GS/OS AppleShare CDEV crash when used | ||||||
|     # with Dayna or Asante bridges |     # with Dayna or Asante bridges | ||||||
|     echo -e 'eth0 -router -phase 2 -net 1 -zone "A2SERVER"' \ |     echo -e 'eth0 -router -phase 2 -net 1 -zone "A2SERVER"' | sudo tee -a /usr/local/etc/netatalk/atalkd.conf > /dev/null | ||||||
|     | sudo tee -a /usr/local/etc/netatalk/atalkd.conf > /dev/null |  | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # Raspberry Pi | # Raspberry Pi | ||||||
| @@ -255,8 +319,8 @@ fi | |||||||
| #    /usr/local/etc/netatalk/AppleVolumes.default | #    /usr/local/etc/netatalk/AppleVolumes.default | ||||||
|  |  | ||||||
| # 1.3.0: if GSFILES is being shared, make directory if not there | # 1.3.0: if GSFILES is being shared, make directory if not there | ||||||
| if grep -q '^/media/A2SHARED/GSFILES' /usr/local/etc/netatalk/AppleVolumes.default; then | if grep -q '^/srv/A2SERVER/GSFILES' /usr/local/etc/netatalk/AppleVolumes.default; then | ||||||
|     [[ -d /media/A2SHARED/GSFILES ]] || mkdir -p /media/A2SHARED/GSFILES; |     [[ -d /srv/A2SERVER/GSFILES ]] || mkdir -p /srv/A2SERVER/GSFILES; | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # prior to 1.3.0: | # prior to 1.3.0: | ||||||
| @@ -268,19 +332,22 @@ fi | |||||||
| # see if shared already uses ciopfs (case-insensitive file system), and convert if not | # see if shared already uses ciopfs (case-insensitive file system), and convert if not | ||||||
| # restore known GS/OS file paths to mixed case | # restore known GS/OS file paths to mixed case | ||||||
| # set up ciopfs (case insensitive file system) for share | # set up ciopfs (case insensitive file system) for share | ||||||
| if [[ -d /media/A2SHARED/A2FILES && ! -d /media/A2SHARED/.a2files ]]; then | if [[ -d /srv/A2SERVER/A2FILES && ! -d /srv/A2SERVER/.a2files ]]; then | ||||||
|     echo "A2SERVER: Converting A2FILES to support mixed case..." |     echo "A2SERVER: Converting A2FILES to support mixed case..." | ||||||
|     sudo /etc/init.d/netatalk stop &> /dev/null |     sudo /etc/init.d/netatalk stop &> /dev/null | ||||||
|     if ! command -v getfattr &> /dev/null; then |     sudo /etc/init.d/samba stop &> /dev/null | ||||||
|  |     if ! hash getfattr &> /dev/null; then | ||||||
|  |         # Dependency: for ciopfs conversion (setfattr) | ||||||
|         sudo apt-get -y install attr &> /dev/null |         sudo apt-get -y install attr &> /dev/null | ||||||
|         sudo apt-get clean |         sudo apt-get clean | ||||||
|     fi |     fi | ||||||
|     rm /media/A2SHARED/A2FILES/.APPLEDESKTOP 2> /dev/null |     rm /srv/A2SERVER/A2FILES/.APPLEDESKTOP 2> /dev/null | ||||||
|     mkdir -p /tmp/netboot |     mkdir -p /tmp/netboot | ||||||
|     a2FilesList="$(wget -qO- http://ivanx.com/a2server/files/A2FILES-list.txt)" |     wget -qO /tmp/A2FILES-list.txt ${binaryURL}A2FILES-list.txt | ||||||
|     find /media/A2SHARED/A2FILES -name '*' | tail -n +2 | tac | while read -d $'\n' thisFile; do |     find /srv/A2SERVER/A2FILES -name '*' | tail -n +2 | tac > /tmp/filelist.txt | ||||||
|  |     while read thisFile; do | ||||||
|         mixedCase="${thisFile##*/}" |         mixedCase="${thisFile##*/}" | ||||||
|         gsosPath=$(grep -i "^${thisFile}$" <<< "$a2FilesList") |         gsosPath=$(grep -i -m 1 "^${thisFile}$" /tmp/A2FILES-list.txt) | ||||||
|         [[ $gsosPath ]] && mixedCase="${gsosPath##*/}" |         [[ $gsosPath ]] && mixedCase="${gsosPath##*/}" | ||||||
|         sudo setfattr -n "user.filename" -v "$mixedCase" "$thisFile" |         sudo setfattr -n "user.filename" -v "$mixedCase" "$thisFile" | ||||||
|         if [[ ${thisFile##*/} != $mixedCase ]]; then |         if [[ ${thisFile##*/} != $mixedCase ]]; then | ||||||
| @@ -288,24 +355,26 @@ if [[ -d /media/A2SHARED/A2FILES && ! -d /media/A2SHARED/.a2files ]]; then | |||||||
|         else |         else | ||||||
|             echo -e "  processing $thisFile\n" |             echo -e "  processing $thisFile\n" | ||||||
|         fi |         fi | ||||||
|         sudo mv "$thisFile" "${thisFile%/*}"/"$(tr [:upper:] [:lower:] <<< $mixedCase)" 2> /dev/null |         sudo mv "$thisFile" "${thisFile%/*}/${mixedCase,,}" 2> /dev/null | ||||||
|     done |     done < /tmp/filelist.txt | ||||||
|     mv /media/A2SHARED/A2FILES /media/A2SHARED/.a2files |     mv /srv/A2SERVER/A2FILES /srv/A2SERVER/.a2files | ||||||
|     mkdir /media/A2SHARED/A2FILES |     mkdir /srv/A2SERVER/A2FILES | ||||||
|     sudo sed -i 's/casefold:toupper //' /usr/local/etc/netatalk/AppleVolumes.default |     sudo sed -i 's/casefold:toupper //' /usr/local/etc/netatalk/AppleVolumes.default 2> /dev/null | ||||||
|     sudo sed -i 's/^VOLCASEFOLD:.*/VOLCASEFOLD:/' /media/A2SHARED/.a2files/.appledesktop/.volinfo |     sudo sed -i 's/^VOLCASEFOLD:.*/VOLCASEFOLD:/' /srv/A2SERVER/.a2files/.appledesktop/.volinfo 2> /dev/null | ||||||
|  |     sudo sed -i 's|/media/A2SHARED/A2FILES|/srv/A2SERVER/A2FILES|' /srv/A2SERVER/.a2files/.appledesktop/.volinfo 2> /dev/null | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # 1.3.0: remove GSFILES if empty | # 1.3.0: remove GSFILES if empty | ||||||
| if grep -q '^/media/A2SHARED/GSFILES' /usr/local/etc/netatalk/AppleVolumes.default; then | if grep -q '^/srv/A2SERVER/GSFILES' /usr/local/etc/netatalk/AppleVolumes.default; then | ||||||
|     gsFilesContents= |     gsFilesContents= | ||||||
|     if [[ -d /media/A2SHARED/GSFILES ]]; then |     if [[ -d /srv/A2SERVER/GSFILES ]]; then | ||||||
|         gsFilesContents="$(find /media/A2SHARED/GSFILES -not -path '*/\.*' | grep -v '^/media/A2SHARED/GSFILES$' | grep -v '^/media/A2SHARED/GSFILES/Network Trash Folder$' | grep -v '^/media/A2SHARED/GSFILES/Temporary Items$')" |         gsFilesContents="$(find /srv/A2SERVER/GSFILES -not -path '*/\.*' | grep -v '^/srv/A2SERVER/GSFILES$' | grep -v '^/srv/A2SERVER/GSFILES/Network Trash Folder$' | grep -v '^/srv/A2SERVER/GSFILES/Temporary Items$')" | ||||||
|         if [[ ! $gsFilesContents ]]; then |         if [[ ! $gsFilesContents ]]; then | ||||||
|             echo "A2SERVER: Removing empty GSFILES shared volume..." |             echo "A2SERVER: Removing empty GSFILES shared volume..." | ||||||
|             sudo /etc/init.d/netatalk stop &> /dev/null |             sudo /etc/init.d/netatalk stop &> /dev/null | ||||||
|             sudo sed -i 's|^/media/A2SHARED/GSFILES.*$|#share1|' /usr/local/etc/netatalk/AppleVolumes.default |             sudo /etc/init.d/samba stop &> /dev/null | ||||||
|             sudo rm -r /media/A2SHARED/GSFILES |             sudo sed -i 's|^/srv/A2SERVER/GSFILES.*$|#share1|' /usr/local/etc/netatalk/AppleVolumes.default | ||||||
|  |             sudo rm -r /srv/A2SERVER/GSFILES | ||||||
|         else |         else | ||||||
|             echo "A2SERVER: GSFILES shared volume has files, leaving as is." |             echo "A2SERVER: GSFILES shared volume has files, leaving as is." | ||||||
|         fi |         fi | ||||||
| @@ -314,20 +383,20 @@ fi | |||||||
|  |  | ||||||
| # set up A2FILES case-insensitive share (for ProDOS 8 files, and GS/OS system) | # set up A2FILES case-insensitive share (for ProDOS 8 files, and GS/OS system) | ||||||
| sudo sed -i \ | sudo sed -i \ | ||||||
|     's/^#share2/\/media\/A2SHARED\/A2FILES\ A2FILES options:prodos\ ea:ad/' \ |     's/^#share2/\/srv\/A2SERVER\/A2FILES\ A2FILES options:prodos\ ea:ad/' \ | ||||||
|         /usr/local/etc/netatalk/AppleVolumes.default |         /usr/local/etc/netatalk/AppleVolumes.default | ||||||
| [[ -d /media/A2SHARED/A2FILES ]] || mkdir -p /media/A2SHARED/A2FILES | [[ -d /srv/A2SERVER/A2FILES ]] || mkdir -p /srv/A2SERVER/A2FILES | ||||||
| [[ -d /media/A2SHARED/.a2files ]] || mkdir -p /media/A2SHARED/.a2files | [[ -d /srv/A2SERVER/.a2files ]] || mkdir -p /srv/A2SERVER/.a2files | ||||||
|  |  | ||||||
| # set up ciopfs | # set up ciopfs | ||||||
| if ! command -v ciopfs > /dev/null; then | if ! hash ciopfs &> /dev/null; then | ||||||
|     echo "A2SERVER: Installing ciopfs (case insensitive file system)..." |     echo "A2SERVER: Installing ciopfs (case insensitive file system)..." | ||||||
|     cd /tmp |     cd /tmp | ||||||
|  |  | ||||||
|  |     # Dependency: For ciopfs | ||||||
|     sudo apt-get -y install fuse libglib2.0-0 libattr1 libfuse2 |     sudo apt-get -y install fuse libglib2.0-0 libattr1 libfuse2 | ||||||
|     if [[ $isRpi ]]; then |     if [[ $arch && ! -f /tmp/a2server-compileAlways ]]; then | ||||||
|         wget -qO- "http://appleii.ivanx.com/a2server/files/ciopfs-rpi.tgz" | sudo tar Pzx |         { wget -qO- "${binaryURL}precompiled/ciopfs-${arch}.tgz" | sudo tar Pzx; } &> /dev/null | ||||||
|     elif [[ $isDebian_x86 ]]; then |  | ||||||
|         wget -qO- "http://appleii.ivanx.com/a2server/files/ciopfs-debian7_x86.tgz" | sudo tar Pzx |  | ||||||
|     fi |     fi | ||||||
|     if [[ -f /etc/fuse.conf ]] && sudo grep -q user_allow_other /etc/fuse.conf; then |     if [[ -f /etc/fuse.conf ]] && sudo grep -q user_allow_other /etc/fuse.conf; then | ||||||
|         sudo sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf |         sudo sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf | ||||||
| @@ -335,21 +404,29 @@ if ! command -v ciopfs > /dev/null; then | |||||||
|         echo "user_allow_other" | sudo tee /etc/fuse.conf > /dev/null |         echo "user_allow_other" | sudo tee /etc/fuse.conf > /dev/null | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     if ! command -v ciopfs > /dev/null; then |     if ! hash ciopfs &> /dev/null; then | ||||||
|         if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then |         if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then | ||||||
|             # prepare for installing packages |             # prepare for installing packages | ||||||
|             sudo apt-get -y update |             sudo apt-get -y update | ||||||
|             touch /tmp/a2server-packageReposUpdated |             touch /tmp/a2server-packageReposUpdated | ||||||
|         fi |         fi | ||||||
|         sudo apt-get -y install build-essential |  | ||||||
|         sudo apt-get -y install libfuse-dev libglib2.0-dev libattr1-dev |         # Dependency: build-dep for ciopfs | ||||||
|  |         sudo apt-get -y install build-essential libfuse-dev libglib2.0-dev libattr1-dev | ||||||
|         sudo apt-get -y clean |         sudo apt-get -y clean | ||||||
|  |  | ||||||
|         cd /tmp |         cd /tmp | ||||||
|         rm -rf /tmp/ciopfs &> /dev/null |         rm -rf /tmp/ciopfs &> /dev/null | ||||||
|         mkdir /tmp/ciopfs |         mkdir /tmp/ciopfs | ||||||
|         cd /tmp/ciopfs |         cd /tmp/ciopfs | ||||||
|  |         if [[ $useExternalURL ]]; then | ||||||
|             wget -q -O ciopfs-0.4.tar.gz http://www.brain-dump.org/projects/ciopfs/ciopfs-0.4.tar.gz |             wget -q -O ciopfs-0.4.tar.gz http://www.brain-dump.org/projects/ciopfs/ciopfs-0.4.tar.gz | ||||||
|         tar zxf ciopfs-0.4.tar.gz |             tar zxf ciopfs-0.4.tar.gz &> /dev/null | ||||||
|  |         fi | ||||||
|  |         if [ ! -f ciopfs*/ciopfs.c ]; then # single brackets required for glob | ||||||
|  |             wget -q -O ciopfs-0.4.tar.gz ${binaryURL}external/source/ciopfs-0.4.tar.gz | ||||||
|  |             tar zxf ciopfs-0.4.tar.gz &> /dev/null | ||||||
|  |         fi | ||||||
|         cd ciopfs* |         cd ciopfs* | ||||||
|         make |         make | ||||||
|         sudo mv ciopfs /usr/local/bin |         sudo mv ciopfs /usr/local/bin | ||||||
| @@ -357,34 +434,36 @@ if ! command -v ciopfs > /dev/null; then | |||||||
|         rm -rf /tmp/ciopfs |         rm -rf /tmp/ciopfs | ||||||
|     fi |     fi | ||||||
|     if ! grep -q '^ciopfs' /etc/fstab; then |     if ! grep -q '^ciopfs' /etc/fstab; then | ||||||
|         echo "ciopfs#/media/A2SHARED/.a2files /media/A2SHARED/A2FILES fuse allow_other 0 0" | sudo tee -a /etc/fstab > /dev/null |         echo "ciopfs#/srv/A2SERVER/.a2files /srv/A2SERVER/A2FILES fuse allow_other 0 0" | sudo tee -a /etc/fstab > /dev/null | ||||||
|     fi |     fi | ||||||
|     if ! mount | grep '^ciopfs.*A2FILES'; then |     if ! mount | grep '^ciopfs.*A2FILES'; then | ||||||
|         sudo ciopfs /media/A2SHARED/.a2files /media/A2SHARED/A2FILES -o allow_other |         sudo ciopfs /srv/A2SERVER/.a2files /srv/A2SERVER/A2FILES -o allow_other | ||||||
|     fi |     fi | ||||||
| else | else | ||||||
|     echo "A2SERVER: ciopfs (case insensitive file system) has already been installed." |     echo "A2SERVER: ciopfs (case insensitive file system) has already been installed." | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if [[ ! -d /media/A2SHARED/A2FILES/.AppleDesktop ]]; then | if [[ ! -d /srv/A2SERVER/A2FILES/.AppleDesktop ]]; then | ||||||
|     cd /media/A2SHARED/A2FILES |     cd /srv/A2SERVER/A2FILES | ||||||
|     mkdir .AppleDesktop |     mkdir .AppleDesktop | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # set up ADTDISKS share (ADTPro disk image folder, if A2CLOUD is installed) | # set up ADTDISKS share (ADTPro disk image folder, if A2CLOUD is installed) | ||||||
| # classic Mac OS file names are allowed (31 chars, mixed case, everything but colons) | # classic Mac OS file names are allowed (31 chars, mixed case, everything but colons) | ||||||
| if [[ -d /usr/local/adtpro/disks ]]; then # A2CLOUD/ADTPro installed | if [[ -d /usr/local/adtpro/disks ]]; then # A2CLOUD/ADTPro installed | ||||||
|     if [[ ! -d /media/A2SHARED/ADTDISKS ]]; then |     if [[ ! -d /srv/A2SERVER/ADTDISKS ]]; then | ||||||
|         ln -s /usr/local/adtpro/disks /media/A2SHARED/ADTDISKS |         ln -s /usr/local/adtpro/disks /srv/A2SERVER/ADTDISKS | ||||||
|     fi |     fi | ||||||
|     if [[ ! $(grep ADTDISKS /usr/local/etc/netatalk/AppleVolumes.default) ]]; then |     if [[ ! $(grep ADTDISKS /usr/local/etc/netatalk/AppleVolumes.default) ]]; then | ||||||
|         sudo sed -i 's@^# End of File@/media/A2SHARED/ADTDISKS ADTDISKS ea:ad\n\n# End of File@' /usr/local/etc/netatalk/AppleVolumes.default |         sudo sed -i 's@^# End of File@/srv/A2SERVER/ADTDISKS ADTDISKS ea:ad\n\n# End of File@' /usr/local/etc/netatalk/AppleVolumes.default | ||||||
|     fi |     fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # to make Netatalk start up when the server boots: | # to make Netatalk start up when the server boots: | ||||||
| sudo update-rc.d netatalk defaults &> /dev/null | sudo update-rc.d netatalk defaults &> /dev/null | ||||||
|  |  | ||||||
|  | # prepare shared volumes for use | ||||||
|  | afpsync -v < /dev/null | ||||||
|  |  | ||||||
| # --- Setting up users | # --- Setting up users | ||||||
|  |  | ||||||
| @@ -398,17 +477,14 @@ if [[ -f /usr/local/etc/netatalk/afppasswd ]]; then | |||||||
| else | else | ||||||
|  |  | ||||||
|     echo |     echo | ||||||
|     echo "A2SERVER: Setting up AFP password 'apple2' for Apple II and Mac clients." |     echo "A2SERVER: Setting up AFP password 'apple2' for Apple II and Mac clients..." | ||||||
|     # echo "A2SERVER: Enter 'apple2' or another password of up to eight characters." |     # echo "A2SERVER: Enter 'apple2' or another password of up to eight characters." | ||||||
|     echo |     echo | ||||||
|     # set registered user login using RandNum authentication |     # set registered user login using RandNum authentication | ||||||
|     sudo afppasswd -c |     sudo afppasswd -c | ||||||
|     sudo sed -i "s/^\(${USER}\).*$/\1:6170706C65320000:****************:********/" /usr/local/etc/netatalk/afppasswd |     sudo sed -i "s/^\(${USER}\).*$/\1:6170706C65320000:****************:********/" /usr/local/etc/netatalk/afppasswd | ||||||
|     # while [[ ! $(sudo afppasswd -a $USER) ]]; do |  | ||||||
|     #     true |  | ||||||
|     # done |  | ||||||
|     # (The afppasswd -c only needs to ever be done once. You can repeat |     # (The afppasswd -c only needs to ever be done once. You can repeat | ||||||
|     #   the afppasswd -a to make Netatalk logins for other Linux users.) |     #   the afppasswd -a to make Netatalk randnum logins for other Linux users.) | ||||||
|  |  | ||||||
| fi | fi | ||||||
|  |  | ||||||
| @@ -416,24 +492,25 @@ fi | |||||||
|  |  | ||||||
| # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) | # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) | ||||||
| kernelRelease=$(uname -r) | kernelRelease=$(uname -r) | ||||||
| kernelMajorRelease=$(cut -d '.' -f 1  <<< $kernelRelease) | kernelMajor=$(cut -d '.' -f 1  <<< $kernelRelease) | ||||||
| kernelMinorRelease=$(cut -d '.' -f 2  <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') | kernelMinor=$(cut -d '.' -f 2  <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') | ||||||
| kernelPatchRelease=$(cut -d '.' -f 3- <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') | kernelPatch=$(cut -d '.' -f 3- <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/') | ||||||
|  | kernelMajorMinor=$(cut -d '.' -f 1-2 <<< $kernelRelease) | ||||||
|  |  | ||||||
| # if on kernel 3.12 through 3.15, check if we need to delete AppleTalk module to prevent kernel panics | # if on kernel 3.12 through 3.15, check if we need to delete AppleTalk module to prevent kernel panics | ||||||
| if [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -ge 12 && $kernelMinorRelease -le 15 ]]; then | if [[ $kernelMajor -eq 3 && $kernelMinor -ge 12 && $kernelMinor -le 15 ]]; then | ||||||
|     # if not RPi, or RPi without ivanx-fixed AppleTalk module, delete the module |     # if not RPi, or RPi without ivanx-fixed AppleTalk module, delete the module | ||||||
|     if [[ ! ( $isRpi && $kernelMinorRelease -eq 12 && $kernelPatchRelease -ge 25 ) ]]; then |     if [[ ! ( $isRpi && $kernelMinor -eq 12 && $kernelPatch -ge 25 ) ]]; then | ||||||
|         if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then |         if [[ -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then | ||||||
|             if [[ $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then |             if [[ $(sha1sum /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then | ||||||
|                 # stop Netatalk |                 # stop Netatalk | ||||||
|                 sudo /etc/init.d/netatalk stop &> /dev/null |                 sudo /etc/init.d/netatalk stop &> /dev/null | ||||||
|                 echo "A2SERVER: Deleting defective AppleTalk kernel module." |                 echo "A2SERVER: Deleting defective AppleTalk kernel module..." | ||||||
|                 sudo rmmod appletalk 2> /dev/null |                 sudo rmmod appletalk 2> /dev/null | ||||||
|                 sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk |                 sudo rm -r /lib/modules/$kernelRelease/kernel/net/appletalk | ||||||
|                 # disable single-user mode on Pi (other Linux can use Recovery boot) |                 # disable single-user mode on Pi (other Linux can use Recovery boot) | ||||||
|                 if [[ $isRpi && $(grep ' single' /boot/cmdline.txt 2> /dev/null) ]]; then |                 if [[ $isRpi && $(grep ' single' /boot/cmdline.txt 2> /dev/null) ]]; then | ||||||
|                     echo "A2SERVER: Disabling single-user mode for next boot." |                     echo "A2SERVER: Disabling single-user mode for next boot..." | ||||||
|                     sudo sed -i 's/ single//' /boot/cmdline.txt |                     sudo sed -i 's/ single//' /boot/cmdline.txt | ||||||
|                     touch /tmp/singleUser # so note to restart can display following install |                     touch /tmp/singleUser # so note to restart can display following install | ||||||
|                 fi |                 fi | ||||||
| @@ -442,6 +519,97 @@ if [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -ge 12 && $kernelMinorRel | |||||||
|     fi |     fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | # if IPDDP module exists (e.g. Debian, but not Raspbian), | ||||||
|  | #   AppleTalk kernel module has been compiled to support it and can't work with MacIP | ||||||
|  | if [[ -f "/lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko" ]]; then | ||||||
|  |     sudo /etc/init.d/netatalk stop &> /dev/null | ||||||
|  |     sudo rmmod ipddp 2> /dev/null | ||||||
|  |     sudo rmmod appletalk 2> /dev/null | ||||||
|  |     echo "A2SERVER: Replacing AppleTalk kernel module (IPDDP disabled) for MacIP use..." | ||||||
|  |  | ||||||
|  |     sudo mv /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko /tmp 2> /dev/null | ||||||
|  |  | ||||||
|  |     if [[ ${arch%_*} == "debian" ]]; then | ||||||
|  |         echo "A2SERVER: Fetching AppleTalk kernel module for Debian..." | ||||||
|  |         wget -qO /tmp/appletalk.tgz ${binaryURL}precompiled/appletalk-$kernelRelease-${arch}.tgz | ||||||
|  |         if [[ $? -eq 0 ]]; then | ||||||
|  |             # if we found a prebuilt one on a2server site, install it and load it | ||||||
|  |             sudo tar Pxf /tmp/appletalk.tgz &> /dev/null | ||||||
|  |             sudo depmod | ||||||
|  |             sudo modprobe appletalk | ||||||
|  |             if [[ $(lsmod | grep appletalk) ]]; then | ||||||
|  |                 # if it loaded, restart netatalk | ||||||
|  |                 sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk | ||||||
|  |                 sudo /etc/init.d/netatalk restart &> /dev/null | ||||||
|  |             else | ||||||
|  |                 # if we didn't load it successfully, remove it | ||||||
|  |                 sudo rm /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko 2> /dev/null | ||||||
|  |             fi | ||||||
|  |         fi | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  |     if ! lsmod | grep -q appletalk; then | ||||||
|  |         # we don't have a prebuilt AppleTalk module, try to build from source | ||||||
|  |         if [[ ! -f /tmp/a2server-packageReposUpdated ]]; then | ||||||
|  |             # prepare for installing packages | ||||||
|  |             sudo apt-get -y update | ||||||
|  |             touch /tmp/a2server-packageReposUpdated | ||||||
|  |         fi | ||||||
|  |  | ||||||
|  |         # kernel module compile adapted from from: http://askubuntu.com/a/338403/288003 | ||||||
|  |         for i in 1; do | ||||||
|  |             echo "A2SERVER: Building AppleTalk kernel module..." | ||||||
|  |             [[ -f /boot/config-$kernelRelease ]] || break | ||||||
|  |             sudo apt-get -y install linux-headers-$kernelRelease linux-source-$kernelMajorMinor || break | ||||||
|  |             sudo apt-get -y install build-essential | ||||||
|  |             cd /usr/src | ||||||
|  |             kernelSrc=$(find linux-source-${kernelMajorMinor}*) | ||||||
|  |             if [[ ${kernelSrc##*.} == "xz" ]]; then | ||||||
|  |                 { xzcat $kernelSrc | sudo tar x; } &> /dev/null | ||||||
|  |             elif [[ ${kernelSrc##*.} == "bz2" ]]; then | ||||||
|  |                 sudo tar jxf $kernelSrc &> /dev/null | ||||||
|  |             elif [[ ${kernelSrc##*.} == "gz" || ${kernelSrc##*.} == "tgz" ]]; then | ||||||
|  |                 sudo tar zxf $kernelSrc &> /dev/null | ||||||
|  |             fi | ||||||
|  |             cd linux-source-$kernelMajorMinor | ||||||
|  |             sudo make mrproper | ||||||
|  |             sudo cp ../linux-headers-$kernelRelease/Module.symvers . | ||||||
|  |             yes '' | sudo make oldconfig | ||||||
|  |             sudo sed -i 's:^.*IPDDP.*$:# CONFIG_IPDDP is not set:gI' .config # disable IPDDP in kernel config | ||||||
|  |             sudo sed -i '$!N; /^\(# CONFIG_IPDDP is not set\)\n\1$/!P; D' .config # delete repeated entries | ||||||
|  |             sudo make prepare | ||||||
|  |             sudo make modules_prepare | ||||||
|  |             sudo make SUBDIRS=scripts/mod | ||||||
|  |             sudo make SUBDIRS=net/appletalk modules | ||||||
|  |             sudo cp net/appletalk/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk | ||||||
|  |             sudo depmod | ||||||
|  |             sudo modprobe appletalk | ||||||
|  |             sudo rm -r /lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko | ||||||
|  |             sudo rmdir /lib/modules/$kernelRelease/kernel/drivers/net/appletalk 2> /dev/null | ||||||
|  |  | ||||||
|  |             # clean up | ||||||
|  |             cd | ||||||
|  |             sudo rm /usr/src/$kernelSrc | ||||||
|  |             sudo rm -r /usr/src/linux-source-$kernelMajorMinor | ||||||
|  |             sudo apt-get -y purge linux-source-$kernelMajorMinor | ||||||
|  |         done | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  |     if [[ $(lsmod | grep appletalk) ]]; then | ||||||
|  |         # if it loaded, make permanent and restart netatalk | ||||||
|  |         sudo rm /lib/modules/$kernelRelease/kernel/drivers/net/appletalk/ipddp.ko 2> /dev/null | ||||||
|  |         sudo sed -i 's:^.*IPDDP.*$:# CONFIG_IPDDP is not set:gI' /boot/config-$kernelRelease | ||||||
|  |         sudo sed -i '$!N; /^\(# CONFIG_IPDDP is not set\)\n\1$/!P; D' /boot/config-$kernelRelease | ||||||
|  |         sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/netatalk; sudo /etc/init.d/netatalk restart &> /dev/null | ||||||
|  |     else | ||||||
|  |         # if we didn't load it successfully, put back the one that was there | ||||||
|  |         echo "A2SERVER: Unable to replace AppleTalk module, replacing original." | ||||||
|  |         sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null | ||||||
|  |         sudo depmod | ||||||
|  |         touch /tmp/noMacIP # to notify at end of install | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
| # --- Start Netatalk (if not running) | # --- Start Netatalk (if not running) | ||||||
|  |  | ||||||
| bground= | bground= | ||||||
| @@ -474,11 +642,11 @@ if [[ ( ! $(ps aux | grep [a]talkd) ) && ( $isRpi ) ]]; then | |||||||
|  |  | ||||||
|     # if no AppleTalk module, try to download it from a2server site |     # if no AppleTalk module, try to download it from a2server site | ||||||
|     if [[ ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # check for rpi kernel module |     if [[ ! -f /lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then # check for rpi kernel module | ||||||
|         echo "A2SERVER: Attempting to install AppleTalk kernel module for Raspbian..." |         echo "A2SERVER: Installing AppleTalk kernel module for Raspbian..." | ||||||
|         wget -qO /tmp/appletalk.ko.gz http://appleii.ivanx.com/a2server/files/appletalk-$kernelRelease.ko.gz |         wget -qO /tmp/appletalk.ko.gz ${binaryURL}appletalk-$kernelRelease-rpi.ko.gz | ||||||
|         if [[ $? -eq 0 ]]; then |         if [[ $? -eq 0 ]]; then | ||||||
|             # if we found a prebuilt one on a2server site, install it and load it |             # if we found a prebuilt one on a2server site, install it and load it | ||||||
|             gunzip -f /tmp/appletalk.ko.gz |             gunzip -f /tmp/appletalk.ko.gz &> /dev/null | ||||||
|             sudo mkdir -p /lib/modules/$kernelRelease/kernel/net/appletalk |             sudo mkdir -p /lib/modules/$kernelRelease/kernel/net/appletalk | ||||||
|             sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk |             sudo mv /tmp/appletalk.ko /lib/modules/$kernelRelease/kernel/net/appletalk | ||||||
|             sudo depmod |             sudo depmod | ||||||
| @@ -539,7 +707,10 @@ if [[ ! $(dpkg -l avahi-daemon 2> /dev/null | grep ^ii) || ! $(dpkg -l libnss-md | |||||||
|         sudo apt-get -y update |         sudo apt-get -y update | ||||||
|         touch /tmp/a2server-packageReposUpdated |         touch /tmp/a2server-packageReposUpdated | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|  |     # Dependency: Bonjour for netatalk | ||||||
|     sudo apt-get -y install avahi-daemon libnss-mdns &> /dev/null |     sudo apt-get -y install avahi-daemon libnss-mdns &> /dev/null | ||||||
|  |  | ||||||
| fi | fi | ||||||
| sudo sed -i 's/^\(hosts.*\)$/\1 mdns/' /etc/nsswitch.conf | sudo sed -i 's/^\(hosts.*\)$/\1 mdns/' /etc/nsswitch.conf | ||||||
| if [[ ! -f /etc/avahi/services/afpd.service && ! -f /etc/avahi/services/afpd.service_disabled ]]; then | if [[ ! -f /etc/avahi/services/afpd.service && ! -f /etc/avahi/services/afpd.service_disabled ]]; then | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -28,8 +28,10 @@ if [[ ! $autoAnswerYes || -f /tmp/a2server-setupWindowsSharing ]]; then | |||||||
|                 touch /tmp/a2server-packageReposUpdated |                 touch /tmp/a2server-packageReposUpdated | ||||||
|             fi |             fi | ||||||
|  |  | ||||||
|  |             # Dependency: samba for Windows/modern Macs | ||||||
|  |             # FIXME: Figure out when smbpasswd moved and adjust this as necessary | ||||||
|             sudo apt-get -y install samba |             sudo apt-get -y install samba | ||||||
|             command -v smbpasswd >/dev/null || sudo apt-get -y install samba-common-bin |             hash smbpasswd &> /dev/null || sudo apt-get -y install samba-common-bin | ||||||
|             sudo apt-get clean |             sudo apt-get clean | ||||||
|         fi |         fi | ||||||
|  |  | ||||||
| @@ -46,13 +48,19 @@ if [[ ! $autoAnswerYes || -f /tmp/a2server-setupWindowsSharing ]]; then | |||||||
|         sudo sed -i 's/^   workgroup = .*$/   workgroup = '$workgroup'/' /etc/samba/smb.conf 2> /dev/null |         sudo sed -i 's/^   workgroup = .*$/   workgroup = '$workgroup'/' /etc/samba/smb.conf 2> /dev/null | ||||||
|         sudo sed -i 's/^#   security = user/   security = user/' /etc/samba/smb.conf 2> /dev/null |         sudo sed -i 's/^#   security = user/   security = user/' /etc/samba/smb.conf 2> /dev/null | ||||||
|  |  | ||||||
|         grep ^/media /usr/local/etc/netatalk/AppleVolumes.default | cut -d" " -f2 \ |         # remove GSFILES if no longer serving it | ||||||
|  |         if ! grep ^/srv/A2SERVER/GSFILES /usr/local/etc/netatalk/AppleVolumes.default; then | ||||||
|  |             sudo sed -i ':a;N;$!ba;s#\n\[GSFILES\].*\[#\n[#' /etc/samba/smb.conf | ||||||
|  |             sudo sed -i ':a;N;$!ba;s#\n\[GSFILES\].*$#\n#' /etc/samba/smb.conf | ||||||
|  |         fi | ||||||
|  |  | ||||||
|  |         grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | cut -d" " -f2 \ | ||||||
|             | while read sharename; do |             | while read sharename; do | ||||||
|             if [[ $(grep $sharename /etc/samba/smb.conf) ]]; then |             if [[ $(grep $sharename /etc/samba/smb.conf) ]]; then | ||||||
|                 echo "A2SERVER: $sharename is already set up for Windows file sharing." |                 echo "A2SERVER: $sharename is already set up for Windows file sharing." | ||||||
|             else |             else | ||||||
|                 echo "[$sharename]" | sudo tee -a /etc/samba/smb.conf > /dev/null |                 echo "[$sharename]" | sudo tee -a /etc/samba/smb.conf > /dev/null | ||||||
|                 echo "    path = /media/A2SHARED/$sharename" | sudo tee -a /etc/samba/smb.conf > /dev/null |                 echo "    path = /srv/A2SERVER/$sharename" | sudo tee -a /etc/samba/smb.conf > /dev/null | ||||||
|                 echo "    browsable = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null |                 echo "    browsable = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null | ||||||
|                 echo "    guest ok = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null |                 echo "    guest ok = yes" | sudo tee -a /etc/samba/smb.conf > /dev/null | ||||||
|                 echo "    read only = no" | sudo tee -a /etc/samba/smb.conf > /dev/null |                 echo "    read only = no" | sudo tee -a /etc/samba/smb.conf > /dev/null | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ password="your password" | |||||||
| [[ $isRaspberryPw ]] && password="'raspberry'" | [[ $isRaspberryPw ]] && password="'raspberry'" | ||||||
|  |  | ||||||
| isDebian= | isDebian= | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1-2 < /etc/debian_version) == "7." ) && ( $(uname -m) == "i686" ) ]] && isDebian=1 | b_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ ( -f /etc/debian_version ) && ( $(cut -d . -f 1 < /etc/debian_version) -ge "7" ) ]] && isDebian=1 | ||||||
|  |  | ||||||
| if [[ $isDebian ]]; then | if [[ $isDebian ]]; then | ||||||
|     if { lspci 2> /dev/null | grep -q VirtualBox; }; then |     if { lspci 2> /dev/null | grep -q VirtualBox; }; then | ||||||
|   | |||||||
							
								
								
									
										180
									
								
								scripts/clock.patch.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										180
									
								
								scripts/clock.patch.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,180 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | '''CLOCK.PATCH by Greg Branche implemented in Python 2/3 for A2SERVER | ||||||
|  |  | ||||||
|  | This is a line-for-line conversion of an edited version of CLOCK.PATCH | ||||||
|  | from the System Tools 2 disk in GS/OS 6.0.1. It's not good Python, | ||||||
|  | but I thought it would be an interesting exercise. In general | ||||||
|  | I have tried replicate each line as closely to BASIC as possible. | ||||||
|  |  | ||||||
|  | Because BASIC substrings are 1-based and python's are 0-based, various | ||||||
|  | indexes are minus one of their BASIC equivalents. | ||||||
|  |  | ||||||
|  | The one change is that you can optionally pass the day and date by | ||||||
|  | command line argument (e.g "Wed 3/13/15"). I also improved error | ||||||
|  | checking. These are in the BASIC lines that don't end in 0. | ||||||
|  |  | ||||||
|  | Rather than modifying PRODOS, this outputs a string of comma-separated | ||||||
|  | year values for a calling script (the a2server-setup installer), | ||||||
|  | followed by a space and a dd-Mmm-yy date string. | ||||||
|  | ''' | ||||||
|  |  | ||||||
|  | # imports for python 3 code compatibility | ||||||
|  | from __future__ import print_function | ||||||
|  | from __future__ import unicode_literals | ||||||
|  | from __future__ import absolute_import | ||||||
|  | from __future__ import division | ||||||
|  |  | ||||||
|  | # other imports | ||||||
|  | import sys | ||||||
|  | import datetime | ||||||
|  |  | ||||||
|  | # substitute raw_input for input in Python2 | ||||||
|  | try: input = raw_input | ||||||
|  | except NameError: pass | ||||||
|  |  | ||||||
|  | dow_str = None | ||||||
|  | day = None | ||||||
|  | if len(sys.argv) > 2: | ||||||
|  |     dow_str = sys.argv[1] # day of week passed on command line | ||||||
|  |     day     = sys.argv[2] # date passed on command line | ||||||
|  |  | ||||||
|  |                                                 # 60000  REM  # of days in each month | ||||||
|  | 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 | ||||||
|  |                                                 # 60020  REM  Names of days of week | ||||||
|  | data += [                                       # 60030  DATA  SUN,MON,TUE,WED,THU,FRI,SAT | ||||||
|  |   "SUN","MON","TUE","WED","THU","FRI","SAT"] | ||||||
|  | data = iter(data) | ||||||
|  |                                                 # 110  REM  cu() = cumulative # of days in year | ||||||
|  | cu = [0] * 13                                   # 120  DIM CU(12) | ||||||
|  |                                                 # 130  REM  fill array with # of days in year | ||||||
|  | cu[1] = 0                                       # 140 CU(1) = 0: REM  January | ||||||
|  | for i in range(2,13):                           # 150  FOR I = 2 TO 12 | ||||||
|  |     x = next(data)                              # 160  READ X | ||||||
|  |     cu[i] = cu[i-1] + x                         # 170 CU(I) = CU(I - 1) + X | ||||||
|  |                                                 # 180  NEXT I | ||||||
|  |  | ||||||
|  |                                                 # 200  REM  DN$() = Names for days of week | ||||||
|  | dn = [""] * 8                                   # 210  DIM DN$(7) | ||||||
|  |                                                 # 220  REM  fill array with names of days of week | ||||||
|  | for i in range(1,8):                            # 230  FOR I = 1 TO 7 | ||||||
|  |     dn[i] = next(data)                          # 240  READ DN$(I) | ||||||
|  |                                                 # 250  NEXT I | ||||||
|  |  | ||||||
|  |                                                 # 270  REM  yt() is the year table values | ||||||
|  | yt = [0] * 8                                    # 280  DIM YT(7) | ||||||
|  |  | ||||||
|  | def mod7(x):                                    # 340  DEF  FN MOD7(X) =  INT (((X / 7) -  INT (X / 7)) * 7 + .5) | ||||||
|  |     return int(((x / 7) -  int(x / 7)) * 7 + .5) | ||||||
|  |  | ||||||
|  | def find_slash_pos(day):                        # 799  REM  Finds position of / within date string | ||||||
|  |     x = -1                                      # 800 X = 0: REM On exit, contains position of /, or 0 if none found | ||||||
|  |     for i in range(0,3):                        # 810  FOR I = 1 TO 3 | ||||||
|  |         if day[i:i+1] == "/": x = i; break      # 820  IF  MID$ (DAY$,I,1) = "/" THEN X = I:I = 3 | ||||||
|  |                                                 # 830  NEXT I | ||||||
|  |     return x                                    # 840  RETURN | ||||||
|  |  | ||||||
|  | while True:                                     # 999  REM  get the user's input and convert | ||||||
|  |     if not day: | ||||||
|  |         print(                                  # 1010  PRINT "Please enter today's date (mm/dd/yy)" | ||||||
|  |           "Please enter today's date (mm/dd/yy)") | ||||||
|  |         day = input("-> ")                      # 1020  INPUT "-> ";DAY$ | ||||||
|  |     x = find_slash_pos(day)                     # 1030  GOSUB 800: REM  find slash separator | ||||||
|  |     input_ok = False | ||||||
|  |     while not input_ok: | ||||||
|  |         if not (x != -1):                       # 1040  IF X <  > 0 THEN 1080 | ||||||
|  |             print(                              # 1050  PRINT "Invalid date entered.  Please try again."; CHR$ (7) | ||||||
|  |               "Invalid date entered.  Please try again.\x07") | ||||||
|  |             break                               # 1060  GOTO 1010 | ||||||
|  |                                                 # 1070  REM  Convert month value to numeric variable | ||||||
|  |         mo = int(day[0:0+x])                    # 1080 MO =  VAL ( MID$ (DAY$,1,X - 1)) | ||||||
|  |         day = day[x+1:]                         # 1090 DAY$ =  MID$ (DAY$,X + 1) | ||||||
|  |         if mo < 1 or mo > 12: x = -1; continue  # 1100  IF MO < 1 OR MO > 12 THEN 1050: REM Range check the month value | ||||||
|  |         x = find_slash_pos(day)                 # 1110  GOSUB 800: REM Parse out the current day | ||||||
|  |         if x == -1: continue                    # 1120  IF X = 0 THEN 1050 | ||||||
|  |                                                 # 1130  REM  Convert day string into numeric value | ||||||
|  |         da = int(day[0:0+x])                    # 1140 DA =  VAL ( MID$ (DAY$,1,X - 1)) | ||||||
|  |         day = day[x+1:]                         # 1150 DAY$ =  MID$ (DAY$,X + 1) | ||||||
|  |         if da < 1 or da > 31: x = -1; continue  # 1160  IF DA < 1 OR DA > 31 THEN 1050: REM Range check the day value | ||||||
|  |         if mo == 2 and da > 29:                 # 1161  IF MO = 2 AND DA > 29 THEN 1050 | ||||||
|  |             x = -1; continue | ||||||
|  |         if (mo == 4 or                          # 1162  IF (MO = 4 OR MO = 6 OR MO = 9 OR MO = 11) AND DA > 30 THEN 1050 | ||||||
|  |             mo == 6 or | ||||||
|  |             mo == 9 or | ||||||
|  |             mo == 11) and da > 30: x = -1; continue | ||||||
|  |                                                 # 1170  REM  Convert year string into numeric value | ||||||
|  |         yr = int(day)                           # 1180 YR =  VAL (DAY$) | ||||||
|  |         if yr < 0 or yr > 99: x = -1; continue  # 1190  IF YR < 0 OR YR > 99 THEN 1050: REM Only allow 0-99 | ||||||
|  |         if yr > 39: yr = yr + 1900              # 1200  IF YR > 39 THEN YR = YR + 1900: REM 40-99 must be 1940-1999 | ||||||
|  |         if yr < 40: yr = yr + 2000              # 1210  IF YR < 40 THEN YR = YR + 2000: REM 0-39 must be 2000-2039 | ||||||
|  |         if ((yr / 4) != int(yr / 4) and         # 1211  IF ((YR / 4) <  >  INT(YR / 4)) AND MO = 2 AND DA > 28 THEN 1050 | ||||||
|  |             mo == 2 and | ||||||
|  |             da > 28): x = -1; continue | ||||||
|  |         input_ok = True | ||||||
|  |     if x != -1: break | ||||||
|  |     else: dow_str = ""; day = "" | ||||||
|  |  | ||||||
|  | while True: | ||||||
|  |     if not dow_str: | ||||||
|  |         print( | ||||||
|  |           "Please enter the day of the week")   # 1230  PRINT "Please enter the day of the week" | ||||||
|  |         dow_str = input("(e.g. Wed) -> ")       # 1240  INPUT "(e.g. Wed) -> ";DOW$ | ||||||
|  |     input_ok = False | ||||||
|  |     while not input_ok: | ||||||
|  |         if not (len(dow_str) >= 3):             # 1250  IF  LEN (DOW$) >  = 3 THEN 1270: REM Must be at least 3 characters | ||||||
|  |             print(                              # 1260  PRINT "Invalid day of week.  Please try again."; CHR$ (7): GOTO 1230 | ||||||
|  |                 "Invalid day of week.  Please try again.\x07") | ||||||
|  |             break | ||||||
|  |         if len(dow_str) > 3:                    # 1270  IF  LEN (DOW$) > 3 THEN DOW$ =  LEFT$ (DOW$,3) | ||||||
|  |             dow_str = dow_str[0:0+3] | ||||||
|  |                                                 # 1280  REM  Shift any lower case letters to upper case | ||||||
|  |         b = ""                                  # 1290 B$ = "" | ||||||
|  |         for i in range(0,3):                    # 1300  FOR I = 1 TO 3 | ||||||
|  |             a = dow_str[i:i+1]                  # 1310 A$ =  MID$ (DOW$,I,1) | ||||||
|  |             if (                                # 1320  IF  ASC (A$) >  =  ASC ("a") AND  ASC (A$) <  =  ASC ("z") THEN A$ =  CHR$ ( ASC (A$) - ( ASC ("a") -  ASC ("A"))) | ||||||
|  |               ord(a) >= ord("a") and ord(a) <= ord("z")): a = chr(ord(a) - (ord("a") -  ord("A"))) | ||||||
|  |             b = b + a                           # 1330 B$ = B$ + A$ | ||||||
|  |                                                 # 1340  NEXT I | ||||||
|  |         dow_str = b                             # 1350 DOW$ = B$ | ||||||
|  |                                                 # 1360  REM  Now convert day-of-week string to numeric value | ||||||
|  |         dow_num = 0                             # 1370 DOW = 0 | ||||||
|  |         for i in range (1,8):                   # 1380  FOR I = 1 TO 7 | ||||||
|  |             if dow_str == dn[i]:                # 1390  IF DOW$ = DN$(I) THEN DOW = I:I = 7 | ||||||
|  |                 dow_num = i; i = 7 | ||||||
|  |                                                 # 1400  NEXT I | ||||||
|  |         if dow_num == 0: dow_str = ""; continue # 1410  IF DOW = 0 THEN 1260 | ||||||
|  |         input_ok = True | ||||||
|  |     if len(dow_str) >= 3: break | ||||||
|  |     else: dow_str = ""; day = "" | ||||||
|  |                                                 # 1430  REM  Calculate the number of days so far this year | ||||||
|  | dys = da + cu[mo]                               # 1440 DYS = DA + CU(MO) | ||||||
|  | oyr = yr | ||||||
|  |                                                 # 1450  REM  Must account for extra day in leap year | ||||||
|  | if ((yr / 4) == int(yr / 4)) and (mo > 2):      # 1460  IF (YR / 4) =  INT (YR / 4) AND MO > 2 THEN DYS = DYS + 1 | ||||||
|  |     dys = dys + 1 | ||||||
|  |  | ||||||
|  |                                                 # 1480  REM  Now calculate the index to use to fill in the table | ||||||
|  | idx = dow_num - mod7(dys) + 1                   # 1490 IDX = DOW -  FN MOD7(DYS) + 1 | ||||||
|  | idx = abs(idx - 10)                             # 1500 IDX =  ABS (IDX - 10) | ||||||
|  | if idx > 7: idx = idx - 7                       # 1510  IF IDX > 7 THEN IDX = IDX - 7 | ||||||
|  |  | ||||||
|  |                                                 # 1530  REM  Now we can fill in the year table | ||||||
|  | for i in range(1,8):                            # 1540  FOR I = 1 TO 7 | ||||||
|  |     if '_i' in vars() and i < (_i + 1): continue    # python: simulate change of i within loop | ||||||
|  |     x = yr - 1900                               # 1550 X = YR - 1900 | ||||||
|  |     if x >= 100: x = x - 100                    # 1560  IF X >  = 100 THEN X = X - 100 | ||||||
|  |     yt[idx] = x                                 # 1570 YT(IDX) = X: REM  store the year into table | ||||||
|  |     idx = idx - 1                               # 1580 IDX = IDX - 1 | ||||||
|  |     if idx < 1: idx = 7                         # 1590  IF IDX < 1 THEN IDX = 7 | ||||||
|  |     if not ((yr / 4) != int(yr / 4)):           # 1600  IF (YR / 4) <  >  INT (YR / 4) THEN 1660: REM  not a leap year | ||||||
|  |         i = i + 1; _i = i                       # 1610 I = I + 1: REM  update index | ||||||
|  |         if i > 7: continue                      # 1620  IF I > 7 THEN 1670: REM  if entire array done, exit | ||||||
|  |         yt[idx] = x                             # 1630 YT(IDX) = X: REM  duplicate entry for leap year | ||||||
|  |         idx = idx - 1                           # 1640 IDX = IDX - 1 | ||||||
|  |         if idx < 1: idx = 7                     # 1650  IF IDX < 1 THEN IDX = 7 | ||||||
|  |     yr = yr + 1                                 # 1660 YR = YR + 1 | ||||||
|  |                                                 # 1670  NEXT I | ||||||
|  |  | ||||||
|  | print(",".join([str(x) for x in yt[1:]]) + " " + | ||||||
|  |       str(da).encode("L1").decode("L1").zfill(2) + "-" + | ||||||
|  |       datetime.date(1900, mo, 1).strftime('%b') + "-" + | ||||||
|  |       str(oyr).encode("L1").decode("L1")[2:]) | ||||||
							
								
								
									
										233
									
								
								scripts/raspbian-update.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								scripts/raspbian-update.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,233 @@ | |||||||
|  | #!/bin/bash | ||||||
|  |  | ||||||
|  | # raspbian-update | ||||||
|  | # updates Raspbian to latest version, including NOOBS if installed | ||||||
|  |  | ||||||
|  | [[ -f /usr/bin/raspi-config ]] && isRpi=1 || isRpi= | ||||||
|  |  | ||||||
|  | if [[ ! $isRpi ]]; then | ||||||
|  |     echo "This ain't a Raspberry Pi." | ||||||
|  |     [[ $0 == "-bash" ]] && return 1 || exit 1 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | skipRepoUpdate= | ||||||
|  | autoYes= | ||||||
|  | updateA2Cloud= | ||||||
|  | updateA2Server= | ||||||
|  | while [[ $1 ]]; do | ||||||
|  |     if [[ $1 == "-r" ]]; then | ||||||
|  |         shift | ||||||
|  |         skipRepoUpdate="-r" | ||||||
|  |     elif [[ $1 == "-y" ]]; then | ||||||
|  |         shift | ||||||
|  |         autoYes="-y" | ||||||
|  |     elif [[ $1 == "-n" ]]; then | ||||||
|  |         shift | ||||||
|  |         noobsOnly="-n" | ||||||
|  |     elif [[ $1 == "a2cloud" ]]; then | ||||||
|  |         shift | ||||||
|  |         updateA2Cloud=1 | ||||||
|  |     elif [[ $1 == "a2server" ]]; then | ||||||
|  |         shift | ||||||
|  |         updateA2Server=1 | ||||||
|  |     elif [[ $1 ]]; then | ||||||
|  |         echo "options:" | ||||||
|  |         echo "-y: auto-answer yes to all prompts and don't prompt for restart" | ||||||
|  |         echo "-r: don't update package repositories" | ||||||
|  |         echo "-n: update NOOBS only; don't update Raspbian" | ||||||
|  |         echo "a2cloud : update A2CLOUD when complete" | ||||||
|  |         echo "a2server: update A2SERVER when complete" | ||||||
|  |         [[ $0 == "-bash" ]] && return 1 || exit 1 | ||||||
|  |     fi | ||||||
|  | done | ||||||
|  |  | ||||||
|  | noobs= | ||||||
|  | readarray -t partitions < <(sudo fdisk -l | grep '^/dev') | ||||||
|  | if [[ \ | ||||||
|  |   ${partitions[0]:0:14} == "/dev/mmcblk0p1" && ${partitions[0]:57:2} == " e" && | ||||||
|  |   ${partitions[1]:0:14} == "/dev/mmcblk0p2" && ${partitions[1]:57:2} == "85" && | ||||||
|  |   ${partitions[2]:0:14} == "/dev/mmcblk0p3" && ${partitions[2]:57:2} == "83" && | ||||||
|  |   ${partitions[3]:0:14} == "/dev/mmcblk0p5" && ${partitions[3]:57:2} == " c" && | ||||||
|  |   ${partitions[4]:0:14} == "/dev/mmcblk0p6" && ${partitions[4]:57:2} == "83" ]]; then | ||||||
|  |     noobs=" and the NOOBS install manager" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | if [[ ! $autoYes ]]; then | ||||||
|  |     echo | ||||||
|  |     echo "You are about to update your SD card to the latest version of the" | ||||||
|  |     echo "Raspbian operating system${noobs}." | ||||||
|  |     echo | ||||||
|  |     echo "This may take an hour or more, and will require restarting when complete." | ||||||
|  |     echo "You might want a backup before continuing in case it doesn't go as planned." | ||||||
|  |     echo | ||||||
|  |     echo -n "Update Raspbian? " | ||||||
|  |     read | ||||||
|  |     if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then | ||||||
|  |         [[ $0 == "-bash" ]] && return 2 || exit 2 | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | origDir="$PWD" | ||||||
|  | cd /tmp | ||||||
|  |  | ||||||
|  | if [[ ! $skipRepoUpdate ]]; then | ||||||
|  |     echo "Updating package repositories..." | ||||||
|  |     sudo apt-get -y update > /dev/null | ||||||
|  | else | ||||||
|  |     echo "Not updating package repositories..." | ||||||
|  |     echo | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | if [[ ! $noobsOnly ]]; then | ||||||
|  |     { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null | ||||||
|  |     freeSpace=$(df / | tail -1 | awk '{ print $4 }') | ||||||
|  |     if (( $freeSpace < 400000 )); then | ||||||
|  |         if dpkg -l | grep -q wolfram-engine; then | ||||||
|  |             if [[ ! $autoYes ]]; then | ||||||
|  |                 echo "In order to create enough space on your SD card to upgrade," | ||||||
|  |                 echo "the Wolfram Language and Mathematica software packages must be removed." | ||||||
|  |                 echo "If you don't know what these are, this won't affect you at all." | ||||||
|  |                 echo | ||||||
|  |                 echo -n "Remove Wolfram software? " | ||||||
|  |                 read | ||||||
|  |                 if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then | ||||||
|  |                     [[ $0 == "-bash" ]] && return 2 || exit 2 | ||||||
|  |                 fi | ||||||
|  |                 sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null | ||||||
|  |                 sudo apt-get -y purge wolfram-engine | ||||||
|  |             else | ||||||
|  |                 echo "Removing Wolfram software due to space constraints..." | ||||||
|  |                 sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null | ||||||
|  |                 sudo apt-get -y purge wolfram-engine | ||||||
|  |             fi | ||||||
|  |         else | ||||||
|  |             echo "You don't have enough free space on your SD card to upgrade." | ||||||
|  |             echo "Sorry, man. Delete some stuff or get a bigger card." | ||||||
|  |             [[ $0 == "-bash" ]] && return 1 || exit 1 | ||||||
|  |         fi | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  |     { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null | ||||||
|  |     dpkg -l | grep -q a2pi && sudo apt-get -y --force-yes install a2pi | ||||||
|  |     dpkg -l | grep -q apple2user && sudo apt-get -y --force-yes install apple2user gsport | ||||||
|  |     if dpkg -l | grep -q wolfram-engine; then | ||||||
|  |         sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null | ||||||
|  |         if [[ $freeSpace -lt 750000 && $(apt-get -s install wolfram-engine | grep upgraded) ]]; then | ||||||
|  |             sudo apt-get -y purge wolfram-engine | ||||||
|  |             { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null | ||||||
|  |         fi | ||||||
|  |         sudo apt-get -y install wolfram-engine | ||||||
|  |         { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null | ||||||
|  |     fi | ||||||
|  |     sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade | ||||||
|  |     { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null | ||||||
|  |     sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade | ||||||
|  |     { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null | ||||||
|  |     sudo apt-get -y install raspberrypi-ui-mods | ||||||
|  |     { cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | if [[ $noobs ]]; then | ||||||
|  |     echo "Updating NOOBS..." | ||||||
|  |  | ||||||
|  |     # update Partition 3 | ||||||
|  |     mkdir -p /tmp/p3 | ||||||
|  |     sudo mount /dev/mmcblk0p3 /tmp/p3 | ||||||
|  |     sudo rm -rf /tmp/p3/os/* 2> /dev/null | ||||||
|  |     if grep -q 'Raspple II' /tmp/p3/installed_os.json; then | ||||||
|  |         echo "Downloading Raspple II lite..." | ||||||
|  |         noobsUrl="ivanx.com/rasppleii/files/RasppleII_lite.zip" | ||||||
|  |         noobsOSurl="ivanx.com/rasppleii/noobs-os" | ||||||
|  |         distDir="Raspple_II" | ||||||
|  |         sudo mkdir -p /tmp/p3/os/$distDir | ||||||
|  |         sudo sed -i 's:/Raspbian:/Raspple_II:' /tmp/p3/installed_os.json | ||||||
|  |         sudo wget -qO /tmp/p3/icon.png $noobsOSurl/Raspple_II.png | ||||||
|  |         { wget -qO- $noobsOSurl/slidesAB.tar | sudo tar -C /tmp/p3/os/$distDir -x; } &> /dev/null | ||||||
|  |     else | ||||||
|  |         echo "Downloading NOOBS lite..." | ||||||
|  |         noobsRoot="downloads.raspberrypi.org/NOOBS_lite/images/" | ||||||
|  |         noobsDir=$(wget -qO- $noobsRoot | grep '^<tr><td' | tail -1 | grep -P -o 'href=".*?"' | cut -c 6- | tr -d '"') | ||||||
|  |         noobsUrl=$noobsRoot$noobsDir$(wget -qO- $noobsRoot$noobsDir | grep -P -o 'href=".*.zip"' | cut -c 6- | tr -d '"') | ||||||
|  |         noobsOSurl="downloads.raspberrypi.org/raspbian" | ||||||
|  |         distDir="Raspbian" | ||||||
|  |         sudo mkdir -p /tmp/p3/os/$distDir | ||||||
|  |         sudo wget -qO /tmp/p3/icon.png $noobsOSurl/Raspbian.png | ||||||
|  |         { wget -qO- $noobsOSurl/marketing.tar | sudo tar -C /tmp/p3/os/$distDir -x; } &> /dev/null | ||||||
|  |     fi | ||||||
|  |     sudo rm -rf /tmp/p3/cache 2> /dev/null | ||||||
|  |     releaseDate=$(wget -qO- $noobsOSurl/os.json | grep 'release_date' | cut -f 4 -d '"') | ||||||
|  |     sudo sed -i 's/"release_date".*$/"release_date" : "'$releaseDate'"/' /tmp/p3/installed_os.json | ||||||
|  |     sudo sed -i 's/keyboard_layout=gb/keyboard_layout=us/' /tmp/p3/noobs.conf | ||||||
|  |     sudo sed -i 's:/mnt/:/settings/:' /tmp/p3/installed_os.json | ||||||
|  |     sudo sed -i 's@"icon".*,@"icon" : "/settings/os/'$distDir'/icon.png",@' /tmp/p3/installed_os.json | ||||||
|  |     sudo cp /tmp/p3/icon.png /tmp/p3/os/$distDir | ||||||
|  |     sudo wget -qO /tmp/p3/os/$distDir/os.json $noobsOSurl/os.json | ||||||
|  |     sudo wget -qO /tmp/p3/os/$distDir/partition_setup.sh $noobsOSurl/partition_setup.sh | ||||||
|  |     sudo wget -qO /tmp/p3/os/$distDir/partitions.json $noobsOSurl/partitions.json | ||||||
|  |     sudo umount /tmp/p3 | ||||||
|  |     rmdir /tmp/p3 | ||||||
|  |  | ||||||
|  |     # update Partition 1 | ||||||
|  |     mkdir -p /tmp/p1 | ||||||
|  |     sudo mount /dev/mmcblk0p1 /tmp/p1 | ||||||
|  |     wget -qO /tmp/noobs_lite.zip $noobsUrl | ||||||
|  |     sudo rm -rf /tmp/p1/* | ||||||
|  |     sudo unzip -d /tmp/p1 /tmp/noobs_lite.zip | ||||||
|  |     sudo sed -i 's/^runinstaller //' /tmp/p1/recovery.cmdline | ||||||
|  |     sudo sed -i 's/silentinstall//' /tmp/p1/recovery.cmdline | ||||||
|  |     grep -q 'keyboard=us' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 keyboard=us/' /tmp/p1/recovery.cmdline | ||||||
|  |     grep -q 'disablesafemode' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 disablesafemode/' /tmp/p1/recovery.cmdline | ||||||
|  |     sudo umount /tmp/p1 | ||||||
|  |     rmdir /tmp/p1 | ||||||
|  |  | ||||||
|  |     sudo sed -i 's/\(Raspple II release.*[^u]$\)/\1u/' /etc/issue | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | echo | ||||||
|  | echo "*** Raspbian update completed. ***" | ||||||
|  | echo | ||||||
|  |  | ||||||
|  | cd /tmp | ||||||
|  |  | ||||||
|  | if [[ $updateA2Cloud ]]; then | ||||||
|  |     wget -qO /tmp/a2cloud-setup ivanx.com/a2cloud/setup/ | ||||||
|  |     source /tmp/a2cloud-setup -y -r noSetGroups | ||||||
|  |     if acmd -g /usr/share/gsport/disks/GSport\ Internet\ Starter\ Kit.2mg SYSTEM/FONTS/SIS.4.10 &> /dev/null; then | ||||||
|  |         wget -qO /tmp/ua2.txt ivanx.com/rasppleii/files/a/ua2.txt | ||||||
|  |         source /tmp/ua2.txt | ||||||
|  |     fi | ||||||
|  |     echo | ||||||
|  |     echo "*** A2CLOUD update completed. ***" | ||||||
|  |     echo | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | cd /tmp | ||||||
|  |  | ||||||
|  | if [[ $updateA2Server ]]; then | ||||||
|  |     wget -q -O /tmp/a2server-setup ivanx.com/a2server/setup/ | ||||||
|  |     if ps aux | grep -q [s]mbd; then | ||||||
|  |         source /tmp/a2server-setup -y -r -w | ||||||
|  |     else | ||||||
|  |         source /tmp/a2server-setup -y -r | ||||||
|  |     fi | ||||||
|  |     echo | ||||||
|  |     echo "*** A2SERVER update completed. ***" | ||||||
|  |     echo | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | cd "$origDir" | ||||||
|  |  | ||||||
|  | if [[ ! $autoYes ]]; then | ||||||
|  |     echo | ||||||
|  |     echo | ||||||
|  |     echo "Your system has been updated and needs to reboot to use its new software." | ||||||
|  |     echo | ||||||
|  |     echo -n "Reboot now (recommended)? " | ||||||
|  |     read | ||||||
|  |     if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then | ||||||
|  |         sudo shutdown -r now | ||||||
|  |     fi | ||||||
|  | else | ||||||
|  |     echo "*** raspbian-update completed. ***" | ||||||
|  |     sudo shutdown -r now | ||||||
|  | fi | ||||||
| @@ -2,17 +2,17 @@ | |||||||
| # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: | ||||||
|  |  | ||||||
| alias a2server-help="more /usr/local/etc/a2server-help.txt" | alias a2server-help="more /usr/local/etc/a2server-help.txt" | ||||||
| alias a2server-setup="wget -q -O /tmp/a2server-setup ${A2SERVER_SCRIPT_URL:-http://appleii.ivanx.com/a2server}$([[ "$A2SERVER_SCRIPT_URL" == */ ]] || echo -n "/")setup/ || { echo \"Can't download A2SERVER setup scripts. Do you has internet?\"; false; } && source /tmp/a2server-setup" | alias a2server-setup='wget -q -O /tmp/a2server-setup ${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current/}setup/index.txt || { echo "Can'"'"'t download A2SERVER setup scripts. Do you has internet?"; false; } && source /tmp/a2server-setup' | ||||||
|  |  | ||||||
| alias a2server-version="cat /usr/local/etc/A2SERVER-version" | alias a2server-version="cat /usr/local/etc/A2SERVER-version" | ||||||
| alias a2server-update="wget -q -O /tmp/a2server-update ${A2SERVER_SCRIPT_URL:-http://appleii.ivanx.com/a2server}$([[ "$A2SERVER_SCRIPT_URL" == */ ]] || echo -n "/")update/ || { echo \"Can't download A2SERVER setup scripts. Do you has internet?\"; false; } && source /tmp/a2server-update" | alias a2server-update='wget -q -O /tmp/a2server-update ${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current/}update/index.txt || { echo "Can'"'"'t download A2SERVER setup scripts. Do you has internet?"; false; } && source /tmp/a2server-update' | ||||||
|  |  | ||||||
| alias system-shutdown='sudo shutdown -h now' | alias system-shutdown='sudo shutdown -h now' | ||||||
| alias system-restart='sudo shutdown -r now' | alias system-restart='sudo shutdown -r now' | ||||||
|  |  | ||||||
|  |  | ||||||
| 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?"' | 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?"' | ||||||
| alias raspbian-update='wget -qO /tmp/raspbian-update ivanx.com/a2server/files/raspbian-update.txt; source /tmp/raspbian-update' | alias raspbian-update='wget -qO /tmp/raspbian-update ${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current/}scripts/raspbian-update.txt || { echo "Can'"'"'t download A2SERVER setup scripts. Do you has internet?"; false; } && source /tmp/raspbian-update' | ||||||
| alias rasppleii-update='raspbian-update a2cloud a2server' | alias rasppleii-update='raspbian-update a2cloud a2server' | ||||||
|  |  | ||||||
| alias welcome-message-edit='sudo nano /etc/motd' | alias welcome-message-edit='sudo nano /etc/motd' | ||||||
| @@ -24,8 +24,8 @@ alias showmac-wifi='ifconfig wlan0 | grep "HWaddr" | cut -dH -f2 | cut -c7-23' | |||||||
| alias ifreset='sudo rm /etc/udev/rules.d/70-persistent-net.rules; echo Interfaces removed. You should system-restart now.' | alias ifreset='sudo rm /etc/udev/rules.d/70-persistent-net.rules; echo Interfaces removed. You should system-restart now.' | ||||||
|  |  | ||||||
| alias netatalk-stop="sudo /etc/init.d/netatalk stop; bonjour-off" | alias netatalk-stop="sudo /etc/init.d/netatalk stop; bonjour-off" | ||||||
| alias netatalk-start="sudo /etc/init.d/netatalk start; bonjour-on" | alias netatalk-start="sudo /etc/init.d/netatalk start; bonjour-on; grep -q 'ATALKD_RUN=yes' /etc/default/netatalk" | ||||||
| alias netatalk-restart="sudo /etc/init.d/netatalk restart; bonjour-on" | alias netatalk-restart="sudo /etc/init.d/netatalk restart; bonjour-on; grep -q 'ATALKD_RUN=yes' /etc/default/netatalk" | ||||||
| alias netatalk-off='sudo /etc/init.d/netatalk stop; bonjour-off; sudo update-rc.d -f netatalk remove &> /dev/null' | alias netatalk-off='sudo /etc/init.d/netatalk stop; bonjour-off; sudo update-rc.d -f netatalk remove &> /dev/null' | ||||||
| alias netatalk-on='sudo update-rc.d netatalk defaults &> /dev/null; bonjour-on; sudo /etc/init.d/netatalk restart' | alias netatalk-on='sudo update-rc.d netatalk defaults &> /dev/null; bonjour-on; sudo /etc/init.d/netatalk restart' | ||||||
|  |  | ||||||
| @@ -33,8 +33,8 @@ alias bonjour-off="sudo mv /etc/avahi/services/afpd.service /etc/avahi/services/ | |||||||
| alias bonjour-on="sudo mv /etc/avahi/services/afpd.service_disabled /etc/avahi/services/afpd.service &> /dev/null" | alias bonjour-on="sudo mv /etc/avahi/services/afpd.service_disabled /etc/avahi/services/afpd.service &> /dev/null" | ||||||
|  |  | ||||||
|  |  | ||||||
| alias netatalk-router-on='sudo sed -i '"'"'s/^eth0.*$/eth0 -router -phase 2 -net 1 -zone "A2SERVER"/'"'"' /usr/local/etc/netatalk/atalkd.conf; sudo sed -i '"'"'s/^wlan0.*$/wlan0 -router -phase 2 -net 1 -zone "A2SERVER"/'"'"' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' | alias netatalk-router-on='sudo sed -i '"'"'s/^\([^# ]*\)\( .*\)$/\1 -router\2 -zone "A2SERVER"/'"'"' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' | ||||||
| alias netatalk-router-off='sudo sed -i '"'"'s/^eth0.*$/eth0/'"'"' /usr/local/etc/netatalk/atalkd.conf; sudo sed -i '"'"'s/^wlan0.*$/wlan0/'"'"' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' | alias netatalk-router-off='sudo sed -i '"'"'s/^\([^#].*\) -router\(.*\) -zone [^ ]*\(.*\)$/\1\2\3/'"'"' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' | ||||||
|  |  | ||||||
|  |  | ||||||
| alias netatalk-eth='sudo sed -i 's/^wlan0/eth0/' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' | alias netatalk-eth='sudo sed -i 's/^wlan0/eth0/' /usr/local/etc/netatalk/atalkd.conf; netatalk-restart' | ||||||
| @@ -47,8 +47,8 @@ alias appletalk-on='sudo sed -i "s/ATALKD_RUN=no/ATALKD_RUN=yes/" /etc/default/n | |||||||
|  |  | ||||||
|  |  | ||||||
| NETATALK="/usr/local/etc/netatalk" | NETATALK="/usr/local/etc/netatalk" | ||||||
| A2FILES="/media/A2SHARED/A2FILES" | A2FILES="/srv/A2SERVER/A2FILES" | ||||||
| GSFILES="/media/A2SHARED/GSFILES" | GSFILES="/srv/A2SERVER/GSFILES" | ||||||
|  |  | ||||||
| alias netboot-gsos="mkatinit -gs -d -f" | alias netboot-gsos="mkatinit -gs -d -f" | ||||||
| alias netboot-gsos-guest="mkatinit -gs -d -f guest" | alias netboot-gsos-guest="mkatinit -gs -d -f guest" | ||||||
| @@ -69,8 +69,8 @@ alias samba-stop='sudo /etc/init.d/samba stop' | |||||||
| alias samba-start='sudo /etc/init.d/samba start' | alias samba-start='sudo /etc/init.d/samba start' | ||||||
| alias samba-restart='sudo /etc/init.d/samba restart' | alias samba-restart='sudo /etc/init.d/samba restart' | ||||||
|  |  | ||||||
| alias a2files-share="sudo sed -i 's/^#share2/\/media\/A2SHARED\/A2FILES\ A2FILES options:prodos ea:ad/' /usr/local/etc/netatalk/AppleVolumes.default; [[ -d /media/A2SHARED/A2FILES ]] || mkdir /media/A2SHARED/A2FILES" | 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" | ||||||
| alias a2files-unshare="sudo sed -i 's/^\/media\/A2SHARED\/A2FILES.*$/#share2/' /usr/local/etc/netatalk/AppleVolumes.default" | alias a2files-unshare="sudo sed -i 's/^\/srv\/A2SERVER\/A2FILES.*$/#share2/' /usr/local/etc/netatalk/AppleVolumes.default" | ||||||
|  |  | ||||||
| alias showalias="alias | cut -d= -f 1 | cut -d' ' -f2 | more" | alias showalias="alias | cut -d= -f 1 | cut -d' ' -f2 | more" | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								scripts/tools/a2serverrc.txt
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								scripts/tools/a2serverrc.txt
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | #! /bin/bash | ||||||
|  | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: | ||||||
|  |  | ||||||
|  | export A2SERVER_SCRIPT_URL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current/}" | ||||||
|  | export A2SERVER_BINARY_URL="${A2SERVER_BINARY_URL:-http://ivanx.com/a2server/files/}" | ||||||
|  | source /usr/local/etc/a2server-aliases | ||||||
| @@ -11,7 +11,7 @@ | |||||||
| # | # | ||||||
| # -v will silently create a .volinfo file if none exists. | # -v will silently create a .volinfo file if none exists. | ||||||
| # If a path is specified, only that volume is synced; otherwise, all | # If a path is specified, only that volume is synced; otherwise, all | ||||||
| # all paths in /media which appear in | # all paths in /srv/A2SERVER which appear in | ||||||
| # /usr/local/etc/netatalk/AppleVolumes.default are synced. | # /usr/local/etc/netatalk/AppleVolumes.default are synced. | ||||||
|  |  | ||||||
| processPath () { | processPath () { | ||||||
| @@ -43,7 +43,6 @@ processPath () { | |||||||
|                 echo "AppleDouble files have been updated for volume $sharepath." |                 echo "AppleDouble files have been updated for volume $sharepath." | ||||||
|             else |             else | ||||||
|                 [[ ! $renameLower ]] && echo "Could not update all files on volume $sharepath." |                 [[ ! $renameLower ]] && echo "Could not update all files on volume $sharepath." | ||||||
|                 [[ ! $renameLower ]] && echo "Ensure filenames are all caps on volume $sharepath." |  | ||||||
|                 if [[ $showerrors ]]; then |                 if [[ $showerrors ]]; then | ||||||
|                     echo $result \ |                     echo $result \ | ||||||
|                         | while read LINE; do |                         | while read LINE; do | ||||||
| @@ -63,7 +62,6 @@ processPath () { | |||||||
|                     $0 $sharepath |                     $0 $sharepath | ||||||
|                 else |                 else | ||||||
|                     echo "Use afpsync -e to see error details." |                     echo "Use afpsync -e to see error details." | ||||||
|                     echo "Use afpsync -r to rename lowercase names to uppercase." |  | ||||||
|                 fi |                 fi | ||||||
|             fi |             fi | ||||||
|             unset IFS |             unset IFS | ||||||
| @@ -108,7 +106,7 @@ else | |||||||
|         #   (as opposed to defaulting to casefold:toupper previously) |         #   (as opposed to defaulting to casefold:toupper previously) | ||||||
|         processPath 1 |         processPath 1 | ||||||
|     else |     else | ||||||
|         grep ^/media /usr/local/etc/netatalk/AppleVolumes.default | \ |         grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | \ | ||||||
|             while read line; do |             while read line; do | ||||||
|             [[ $(echo $line | grep toupper) ]]; nocasefold=$? |             [[ $(echo $line | grep toupper) ]]; nocasefold=$? | ||||||
|             sharepath=$(echo $line | cut -d" " -f1) |             sharepath=$(echo $line | cut -d" " -f1) | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -49,7 +49,7 @@ else | |||||||
|     if [[ $1 ]]; then |     if [[ $1 ]]; then | ||||||
|         sharepath=$(readlink -m $1) |         sharepath=$(readlink -m $1) | ||||||
|     else |     else | ||||||
|         sharepath=$(grep ^/media /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) |         sharepath=$(grep ^/srv/A2SERVER /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     volinfo=$sharepath/.AppleDesktop/.volinfo |     volinfo=$sharepath/.AppleDesktop/.volinfo | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								scripts/tools/netatalk-maketar.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								scripts/tools/netatalk-maketar.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										136
									
								
								setup/index.txt
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								setup/index.txt
									
									
									
									
									
								
							| @@ -4,34 +4,48 @@ | |||||||
| # A2SERVER master setup script, last update 17-Nov-15 | # A2SERVER master setup script, last update 17-Nov-15 | ||||||
| # it downloads and executes several scripts related to the setup of | # it downloads and executes several scripts related to the setup of | ||||||
| # netatalk configured for Apple II use on Debian or Raspbian. | # netatalk configured for Apple II use on Debian or Raspbian. | ||||||
| # more info is at http://appleii.ivanx.com/a2server | # more info is at http://ivanx.com/a2server | ||||||
|  |  | ||||||
| # to download and execute, type: | # to download and execute, type: | ||||||
| # wget appleii.ivanx.com/a2server/setup; source setup | # wget ivanx.com/a2server/setup; source setup | ||||||
|  |  | ||||||
| a2serverVersion="127" | a2serverVersion="150" | ||||||
|  |  | ||||||
| # Ensure URL we'll use ends in a / | # Ensure URL we'll use ends in a / | ||||||
| case "$A2SERVER_SCRIPT_URL" in | case "$A2SERVER_SCRIPT_URL" in | ||||||
| 	*/) scriptURL="$A2SERVER_SCRIPT_URL" ;; | 	*/) scriptURL="$A2SERVER_SCRIPT_URL" ;; | ||||||
| 	*) scriptURL="${A2SERVER_SCRIPT_URL:-http://appleii.ivanx.com/a2server}/" ;; | 	*) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current}/" ;; | ||||||
| esac | esac | ||||||
|  | case "$A2SERVER_BINARY_URL" in | ||||||
|  | 	*/) binaryURL="$A2SERVER_BINARY_URL" ;; | ||||||
|  | 	*) binaryURL="${A2SERVER_BINARY_URL:-http://ivanx.com/a2server/files}/" ;; | ||||||
|  | esac | ||||||
|  | useExternalURL=1 | ||||||
|  | [[ $A2SERVER_NO_EXTERNAL ]] && useExternalURL= | ||||||
|  |  | ||||||
| isRpi= | isRpi= | ||||||
| [[ -f /usr/bin/raspi-config ]] && isRpi=1 | [[ -f /usr/bin/raspi-config ]] && isRpi=1 | ||||||
|  |  | ||||||
| isDebian= | isDebian= | ||||||
| [[ ( -f /etc/debian_version ) && ( $(cut -c 1-2 < /etc/debian_version) == "7." ) && ( $(uname -m) == "i686" ) ]] && isDebian=1 | lsb_release -a 2> /dev/null | grep -q 'Distributor ID:.Debian' && [[ ( -f /etc/debian_version ) && ( $(cut -d . -f 1 < /etc/debian_version) -ge "7" ) ]] && isDebian=1 | ||||||
|  |  | ||||||
| if [[ -f /usr/local/etc/A2SERVER-version ]]; then | if [ -f /usr/local/etc/A2SERVER-version ]; then | ||||||
|     echo "A2SERVER version available: $a2serverVersion" |     installedVersion="$(cat /usr/local/etc/A2SERVER-version)" | ||||||
|     echo "A2SERVER version installed: $(cat /usr/local/etc/A2SERVER-version)" |  | ||||||
| fi | fi | ||||||
|  | echo "A2SERVER version available: $a2serverVersion" | ||||||
|  | echo "A2SERVER version installed: ${installedVersion:=None}" | ||||||
|  |  | ||||||
|  | echo | ||||||
|  | [[ $scriptURL != *"ivanx.com"* && $scriptURL != *"raw.githubusercontent.com/RasppleII/a2server"* ]] && echo "Using script URL: $scriptURL" | ||||||
|  | [[ $binaryURL != *"ivanx.com"* ]] && echo "Using binary URL: $binaryURL" | ||||||
|  | [[ ! $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.)" | ||||||
|  |  | ||||||
| skipRepoUpdate= | skipRepoUpdate= | ||||||
| autoAnswerYes= | autoAnswerYes= | ||||||
|  | installAll= | ||||||
| setupNetBoot= | setupNetBoot= | ||||||
| setupWindowsSharing= | setupWindowsSharing= | ||||||
|  | compileAlways= | ||||||
| updateRasppleII= | updateRasppleII= | ||||||
| rm /tmp/a2server-* 2> /dev/null | rm /tmp/a2server-* 2> /dev/null | ||||||
| while [[ $1 ]]; do | while [[ $1 ]]; do | ||||||
| @@ -39,6 +53,9 @@ while [[ $1 ]]; do | |||||||
|         shift |         shift | ||||||
|         skipRepoUpdate="-r" |         skipRepoUpdate="-r" | ||||||
|         touch /tmp/a2server-packageReposUpdated |         touch /tmp/a2server-packageReposUpdated | ||||||
|  |     elif [[ $1 == "-i" ]]; then | ||||||
|  |         shift | ||||||
|  |         installAll="-i" | ||||||
|     elif [[ $1 == "-y" ]]; then |     elif [[ $1 == "-y" ]]; then | ||||||
|         shift |         shift | ||||||
|         autoAnswerYes="-y" |         autoAnswerYes="-y" | ||||||
| @@ -51,24 +68,27 @@ while [[ $1 ]]; do | |||||||
|         shift |         shift | ||||||
|         setupWindowsSharing="-w" |         setupWindowsSharing="-w" | ||||||
|         touch /tmp/a2server-setupWindowsSharing |         touch /tmp/a2server-setupWindowsSharing | ||||||
|  |     elif [[ $1 == "-c" ]]; then | ||||||
|  |         shift | ||||||
|  |         compileAlways="-c" | ||||||
|  |         touch /tmp/a2server-compileAlways | ||||||
|     elif [[ $1 == "-os" || $1 == "os" ]]; then |     elif [[ $1 == "-os" || $1 == "os" ]]; then | ||||||
|         # elif [[ ${1,,} == "rasppleii" || ${1,,} == "raspple" || ${1,,} == "rasappleii" || ${1,,} == "rasapple" || ${1,,} == "raspple2" || ${1,,} == "rasapple2" ]]; then |         # elif [[ ${1,,} == "rasppleii" || ${1,,} == "raspple" || ${1,,} == "rasappleii" || ${1,,} == "rasapple" || ${1,,} == "raspple2" || ${1,,} == "rasapple2" ]]; then | ||||||
|         shift |         shift | ||||||
|         updateRasppleII=1 |         updateRasppleII=1 | ||||||
|     elif [[ $1 == "-v" ]]; then |     elif [[ $1 == "-v" ]]; then | ||||||
|         shift |         shift | ||||||
|         if [[ ! -f /usr/local/etc/A2SERVER-version ]]; then |         # Version was already printed | ||||||
|             echo "A2SERVER version available: $a2serverVersion" |  | ||||||
|             echo "A2SERVER version installed: none" |  | ||||||
|         fi |  | ||||||
|         [[ $0 == "-bash" ]] && return 1 || exit 1 |         [[ $0 == "-bash" ]] && return 1 || exit 1 | ||||||
|     elif [[ $1 ]]; then |     elif [[ $1 ]]; then | ||||||
|         echo "options:" |         echo "options:" | ||||||
|         echo "-v: display installed and available versions, then exit" |         echo "-v: display installed and available versions, then exit" | ||||||
|  |         echo "-i: reinstall A2SERVER software (but not Apple II software)" | ||||||
|         echo "-y: auto-answer yes to all prompts" |         echo "-y: auto-answer yes to all prompts" | ||||||
|         echo "-r: don't update package repositories" |         echo "-r: don't update package repositories" | ||||||
|         echo "-b: auto-setup network boot (use with -y)" |         echo "-b: auto-setup network boot (use with -y)" | ||||||
|         echo "-w: auto-setup Windows file sharing (use with -y)" |         echo "-w: auto-setup Windows file sharing (use with -y)" | ||||||
|  |         echo "-c: compile non-package items, rather than downloading binaries" | ||||||
|         if [[ $isRpi ]]; then |         if [[ $isRpi ]]; then | ||||||
|             echo "-os: update Raspbian OS, A2CLOUD, A2SERVER, and Apple II Pi" |             echo "-os: update Raspbian OS, A2CLOUD, A2SERVER, and Apple II Pi" | ||||||
|         fi |         fi | ||||||
| @@ -78,12 +98,12 @@ done | |||||||
|  |  | ||||||
| if [[ $updateRasppleII ]]; then | if [[ $updateRasppleII ]]; then | ||||||
|     echo "A2SERVER: Updating Raspple II (takes up to an hour)..." |     echo "A2SERVER: Updating Raspple II (takes up to an hour)..." | ||||||
|     wget -qO /tmp/raspbian-update "http://appleii.ivanx.com/a2server/files/raspbian-update.txt" |     wget -qO /tmp/raspbian-update "${A2SERVER_SCRIPT_URL}scripts/raspbian-update.txt" | ||||||
|     source /tmp/raspbian-update a2cloud a2server $autoAnswerYes $skipRepoUpdate |     source /tmp/raspbian-update a2cloud a2server $autoAnswerYes $skipRepoUpdate | ||||||
|     [[ $0 == "-bash" ]] && return 0 || exit 0 |     [[ $0 == "-bash" ]] && return 0 || exit 0 | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if { [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(cat /usr/local/etc/A2SERVER-version) < 110 )); }; then | if { [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) < 110 )); }; then | ||||||
|     echo |     echo | ||||||
|     echo "WARNING: The current A2SERVER installer scripts haven't been tested for" |     echo "WARNING: The current A2SERVER installer scripts haven't been tested for" | ||||||
|     echo "updating the earlier version of A2SERVER that you have. A fresh install" |     echo "updating the earlier version of A2SERVER that you have. A fresh install" | ||||||
| @@ -94,29 +114,47 @@ fi | |||||||
| a2server_update=0 | a2server_update=0 | ||||||
| doSetup=1 | doSetup=1 | ||||||
|  |  | ||||||
|  | if { [[ -f /usr/local/etc/A2SERVER-version ]] && (( $(head -c 3 /usr/local/etc/A2SERVER-version) < 150 )); }; then | ||||||
|  |     a2server_update=1 | ||||||
|  | fi | ||||||
|  |  | ||||||
| unsupportedOS=1 | unsupportedOS=1 | ||||||
| if [[ $isRpi ]]; then #supported Raspbian? (16-Feb-15, 20-Jun-14, 09-Jan-14, etc) | if [[ $isRpi ]]; then #supported Raspbian? (16-Feb-15, 20-Jun-14, 09-Jan-14, etc) | ||||||
|     fwhash=$(zcat /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | grep -m 1 'as of' | awk '{print $NF}') |     fwhash=$(zcat /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | grep -m 1 'as of' | awk '{print $NF}') | ||||||
|     fwsupported="-8aca5762- -462f3e3f476f7b6- -c32bc633039cd9- -9d34d0475f9- |     fwsupported="-8aca5762- -462f3e3f476f7b6- -c32bc633039cd9- -9d34d0475f9- | ||||||
|             -d4f5315cfac4e- -6f4a90c8cb8817f- -5dd9b4962e- -17c8799375- |             -d4f5315cfac4e- -6f4a90c8cb8817f- -5dd9b4962e- -17c8799375- | ||||||
|             -960832a6c2590635216c296b6ee0bebf67b21d50-" |             -960832a6c2590635216c296b6ee0bebf67b21d50- | ||||||
|     [[ "$fwsupported" == *-$fwhash-* ]] && unsupportedOS=0 |             -2a329e0c7d8ea19c085bac5633aa4fccee0f21be-" | ||||||
|     [[ ($fwhash == "8aca5762") || ($fwhash == "462f3e3f476f7b6") || ($fwhash == "c32bc633039cd9") || ($fwhash == "9d34d0475f9") || ($fwhash == "d4f5315cfac4e") || ($fwhash == "6f4a90c8cb8817f") || ($fwhash == "5dd9b4962e") || ($fwhash == "17c8799375") ]] && unsupportedOS=0 |     [[ "$fwsupported" == *-$fwhash-* ]] && unsupportedOS= | ||||||
| elif [[ "$(lsb_release -rs 2> /dev/null)" == "7.3" || "$(lsb_release -rs 2> /dev/null)" == "7.6" || "$(lsb_release -rs 2> /dev/null)" == "7.8" ]]; then # tested Debian? |     # [[ ($fwhash == "8aca5762") || ($fwhash == "462f3e3f476f7b6") || ($fwhash == "c32bc633039cd9") || ($fwhash == "9d34d0475f9") || ($fwhash == "d4f5315cfac4e") || ($fwhash == "6f4a90c8cb8817f") || ($fwhash == "5dd9b4962e") || ($fwhash == "17c8799375") ]] && unsupportedOS= | ||||||
|     unsupportedOS=0 | elif [[ $isDebian ]]; then # supported Debian? | ||||||
|  |      debianVersion=$(cat /etc/debian_version) | ||||||
|  |      debianSupported="-8.2- -7.9- -7.8- -7.6- -7.3-" | ||||||
|  |      [[ $debianSupported == *-$debianVersion-* ]] && unsupportedOS= | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if (( unsupportedOS )); then | if [[ $unsupportedOS && $isRpi ]]; then | ||||||
|     echo |     echo | ||||||
|     echo "WARNING: A2SERVER and its installer scripts have not been tested on this" |     echo "A2SERVER and its installer scripts have been tested on Raspbian Wheezy and" | ||||||
|     echo "operating system version. Continuing is probably fine, but might not be." |     echo "Jessie, though not this specific firmware version ($fwhash). Just FYI." | ||||||
|     echo "Worst case could make your operating system no longer work properly," |     unsupportedOS= | ||||||
|     echo "or cause data to be lost." | elif [[ $unsupportedOS && $isDebian ]]; then | ||||||
|     echo "More information is at http://appleii.ivanx.com/a2server." |     echo | ||||||
|  |     echo "A2SERVER and its installer scripts have been tested on Debian 7 and 8," | ||||||
|  |     echo "though not this specific point release ($debianVersion). Just FYI." | ||||||
|  |     unsupportedOS= | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | if [[ $unsupportedOS ]]; then | ||||||
|  |     echo | ||||||
|  |     echo "WARNING: A2SERVER and its installer scripts have only been tested on" | ||||||
|  |     echo "Debian and Raspbian. Continuing is probably fine, but might not be." | ||||||
|  |     echo "Theoretical worst case would be your operating system no longer works" | ||||||
|  |     echo "properly or data is lost, so consider backing up first." | ||||||
| fi | fi | ||||||
|  |  | ||||||
| doSetup=1 | doSetup=1 | ||||||
| if [[ ! -f /usr/local/etc/a2server-help.txt ]] || (( $a2server_update )); then | if [[ $installAll || ! -f /usr/local/etc/a2server-help.txt ]] || (( $a2server_update )); then | ||||||
|     echo |     echo | ||||||
|     echo "Setting up A2SERVER will take up to 60 minutes, during which" |     echo "Setting up A2SERVER will take up to 60 minutes, during which" | ||||||
|     echo "you'll see a bunch of stuff spit out across the screen." |     echo "you'll see a bunch of stuff spit out across the screen." | ||||||
| @@ -132,7 +170,7 @@ if (( $doSetup )); then | |||||||
|  |  | ||||||
|     echo |     echo | ||||||
|     echo "a2server-setup modifies files and performs actions as the root user." |     echo "a2server-setup modifies files and performs actions as the root user." | ||||||
|     echo "For details, visit http://appleii.ivanx.com/a2server." |     echo "For details, visit http://ivanx.com/a2server." | ||||||
|     echo |     echo | ||||||
|     if [[ ! $autoAnswerYes ]]; then |     if [[ ! $autoAnswerYes ]]; then | ||||||
|         echo -n "Continue? " |         echo -n "Continue? " | ||||||
| @@ -156,7 +194,7 @@ if (( $doSetup )); then | |||||||
|             if [[ ! $autoAnswerYes ]]; then |             if [[ ! $autoAnswerYes ]]; then | ||||||
|                 echo |                 echo | ||||||
|                 echo "To ensure that all client computers are able to connect to" |                 echo "To ensure that all client computers are able to connect to" | ||||||
|                 echo "${a2server} using the same password, you are recommended" |                 echo "${a2server} using the same password, you probably want" | ||||||
|                 echo "to change your user password to 'apple2'." |                 echo "to change your user password to 'apple2'." | ||||||
|                 echo |                 echo | ||||||
|                 echo -n "Do you want to change the password for user '$USER' to 'apple2' now? " |                 echo -n "Do you want to change the password for user '$USER' to 'apple2' now? " | ||||||
| @@ -197,6 +235,16 @@ if (( $doSetup )); then | |||||||
|  |  | ||||||
|         echo "A2SERVER: Scripts have been downloaded. Installing..." |         echo "A2SERVER: Scripts have been downloaded. Installing..." | ||||||
|  |  | ||||||
|  |         if [[ $installAll ]]; then | ||||||
|  |             sudo rm /usr/local/etc/A2SERVER-version 2> /dev/null | ||||||
|  |             sudo rm /usr/local/bin/nulib2 2> /dev/null | ||||||
|  |             sudo rm /usr/local/bin/unar 2> /dev/null | ||||||
|  |             sudo rm /usr/local/sbin/macipgw 2> /dev/null | ||||||
|  |             sudo rm /usr/local/bin/ciopfs 2> /dev/null | ||||||
|  |             sudo rm /usr/local/etc/netatalk/afppasswd 2> /dev/null | ||||||
|  |             sudo rm /usr/local/etc/netatalk/a2boot/p8 /usr/local/etc/netatalk/a2boot/ProDOS16\ Image 2> /dev/null | ||||||
|  |         fi | ||||||
|  |  | ||||||
|         /tmp/1.storage |         /tmp/1.storage | ||||||
|         rm /tmp/1.storage |         rm /tmp/1.storage | ||||||
|         /tmp/2.tools |         /tmp/2.tools | ||||||
| @@ -212,11 +260,11 @@ if (( $doSetup )); then | |||||||
|         rm /tmp/a2server-packageReposUpdated &> /dev/null |         rm /tmp/a2server-packageReposUpdated &> /dev/null | ||||||
|  |  | ||||||
|         if [[ ! -f /usr/local/etc/A2SERVER-version ]] \ |         if [[ ! -f /usr/local/etc/A2SERVER-version ]] \ | ||||||
|             || (( $(cat /usr/local/etc/A2SERVER-version) < "$a2serverVersion" )); then |             || (( $(head -c 3 /usr/local/etc/A2SERVER-version) < ${a2serverVersion:0:3} )); then | ||||||
|             echo "$a2serverVersion" | sudo tee /usr/local/etc/A2SERVER-version &> /dev/null |             echo "$a2serverVersion" | sudo tee /usr/local/etc/A2SERVER-version &> /dev/null | ||||||
|         fi |         fi | ||||||
|  |  | ||||||
|         source /usr/local/etc/a2server-aliases |         source /usr/local/etc/a2serverrc | ||||||
|  |  | ||||||
|         # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) |         # get Kernel release (e.g. 3.6.11+) and version (e.g. #557) | ||||||
|         kernelRelease=$(uname -r) |         kernelRelease=$(uname -r) | ||||||
| @@ -230,7 +278,20 @@ if (( $doSetup )); then | |||||||
|             echo "On an Apple IIe, it should be accessible via \"Log In\" on the" |             echo "On an Apple IIe, it should be accessible via \"Log In\" on the" | ||||||
|             echo "Workstation Card software. For IIgs users, it should be accessible" |             echo "Workstation Card software. For IIgs users, it should be accessible" | ||||||
|             echo "via the AppleShare control panel." |             echo "via the AppleShare control panel." | ||||||
|  |             if [[ -f /srv/A2SERVER/A2FILES/System/Start.GS.OS ]]; then | ||||||
|                 echo |                 echo | ||||||
|  |                 echo "You can network boot GS/OS." | ||||||
|  |                 echo "On a ROM 01 IIgs, set slot 1 (printer port), or slot 2 (modem port)" | ||||||
|  |                 echo "to Your Card, and slot 7 to AppleTalk, and Startup Slot to 7 or Scan." | ||||||
|  |                 echo "On a ROM 3 IIgs, set slot 1 or 2, and Startup Slot, to AppleTalk." | ||||||
|  |             fi | ||||||
|  |             if [[ -f /srv/A2SERVER/A2FILES/BASIC.System ]]; then | ||||||
|  |                 echo | ||||||
|  |                 echo "You can network boot ProDOS 8. On an Apple IIe, put your Workstation Card" | ||||||
|  |                 echo "in a slot above your disk controller card, or type PR#X with open-apple" | ||||||
|  |                 echo "held down, with X being the slot of your Workstation Card." | ||||||
|  |                 echo 'On a IIgs, press "8" during the initial procession of periods.' | ||||||
|  |             fi | ||||||
|             echo |             echo | ||||||
|             echo "A2SERVER setup is complete! Go connect from your Apple II!" |             echo "A2SERVER setup is complete! Go connect from your Apple II!" | ||||||
|             echo |             echo | ||||||
| @@ -267,8 +328,17 @@ if (( $doSetup )); then | |||||||
|             echo |             echo | ||||||
|         fi |         fi | ||||||
|  |  | ||||||
|  |         if [[ -f /tmp/noMacIP ]]; then | ||||||
|  |             echo | ||||||
|  |             echo "MacIP connections may be unavailable. If you know how, try" | ||||||
|  |             echo "recompiling the AppleTalk kernel module with IPDDP options disabled." | ||||||
|  |             echo | ||||||
|  |             rm /tmp/noMacIP | ||||||
|  |         fi | ||||||
|  |  | ||||||
|         if [[ -f /tmp/singleUser ]]; then |         if [[ -f /tmp/singleUser ]]; then | ||||||
|             if [[ ! $autoAnswerYes ]]; then |             if [[ ! $autoAnswerYes ]]; then | ||||||
|  |                 echo | ||||||
|                 echo "Your Raspberry Pi was started in single-user mode in order to" |                 echo "Your Raspberry Pi was started in single-user mode in order to" | ||||||
|                 echo -n "fix a problem. You should restart to operate normally. Restart now? " |                 echo -n "fix a problem. You should restart to operate normally. Restart now? " | ||||||
|                 read |                 read | ||||||
| @@ -279,6 +349,7 @@ if (( $doSetup )); then | |||||||
|                 echo "A2SERVER: Preparing to restart..." |                 echo "A2SERVER: Preparing to restart..." | ||||||
|                 while :; do sleep 60; done |                 while :; do sleep 60; done | ||||||
|             fi |             fi | ||||||
|  |             rm /tmp/singleUser | ||||||
|             echo |             echo | ||||||
|         fi |         fi | ||||||
|  |  | ||||||
| @@ -291,8 +362,5 @@ fi | |||||||
|  |  | ||||||
| unset a2server_update 2> /dev/null | unset a2server_update 2> /dev/null | ||||||
| unset doSetup 2> /dev/null | unset doSetup 2> /dev/null | ||||||
| rm /tmp/a2server-autoAnswerYes 2> /dev/null | rm /tmp/a2server-* 2> /dev/null | ||||||
| rm /tmp/a2server-packageReposUpdated 2> /dev/null |  | ||||||
| rm /tmp/a2server-setupNetBoot 2> /dev/null |  | ||||||
| rm /tmp/a2server-setupWindowsSharing 2> /dev/null |  | ||||||
| rm setup &> /dev/null | rm setup &> /dev/null | ||||||
|   | |||||||
| @@ -49,3 +49,53 @@ | |||||||
| 1.2.3: May 2015: changed Apple software links to Internet Archive | 1.2.3: May 2015: changed Apple software links to Internet Archive | ||||||
| 
 | 
 | ||||||
| 1.2.4: Jul 2015: offer to download A2CLOUD disk contents onto A2FILES volume | 1.2.4: Jul 2015: offer to download A2CLOUD disk contents onto A2FILES volume | ||||||
|  | 
 | ||||||
|  | 1.2.4+:Oct 2015: support for using A2SERVER scripts from a location other than | ||||||
|  | [unannounced]    ivanx.com/a2server for development purposes | ||||||
|  | 
 | ||||||
|  | 1.2.5: Nov 2015: netboot install option for GS/OS 6.0.2/3 | ||||||
|  |                  netboot always downloads GS/OS disk images even if present | ||||||
|  |                  provides error if a2setup doesn't have internet | ||||||
|  |                  remove persisting a2server-setup options after aborted install | ||||||
|  |                  fixed installer bug that omits first and last script elements | ||||||
|  |                  download images from Apple, with Internet Archive as a backup | ||||||
|  |                  install HFS.FST during netboot install | ||||||
|  | 
 | ||||||
|  | 1.2.5+:Nov 2015: Merged Ivan's 1.2.5 release, removed support for Ubuntu for | ||||||
|  | [unannounced]    now (see RasppleII/a2server#11), patched ProDOS 8 in boot | ||||||
|  |                  files for current year table, install unar from a package if | ||||||
|  |                  it exists. | ||||||
|  | 
 | ||||||
|  | 1.2.6: Nov 2015: full, ready to use install of Spectrum; install unzip | ||||||
|  | [unannounced] | ||||||
|  | 
 | ||||||
|  | 1.2.6+:Nov 2015: merged Ivan's 1.2.6 (into github master branch) | ||||||
|  | [unannounced] | ||||||
|  | 
 | ||||||
|  | 1.2.7: Dec 2015: preliminary Jessie support; case insensitive file system for | ||||||
|  | [unannounced]    A2FILES; removes GSFILES if empty; DOS3.3.FST and TEACH are | ||||||
|  |                  installed with netboot installation; minor bug fixes and | ||||||
|  |                  tweaks; Ubuntu support removed; branches unified | ||||||
|  | 
 | ||||||
|  | 1.2.8: Dec 2015: can specify alternate host for binaries and external files; | ||||||
|  | [unannounced]    64-bit Debian precompiled binaries; move /media/A2SHARED/* | ||||||
|  |                  to /srv/A2SERVER; internet access (MacIP support); | ||||||
|  | 
 | ||||||
|  | 1.2.9: Jan 2016: cppo supports ShrinkIt, DOS 3.3, DSK, 2MG; MountIt fully | ||||||
|  | [unannounced]    installed; nulib2 fixes handling empty forks (thanks Andy); | ||||||
|  |                  -c installer option compiles all software (no binaries) | ||||||
|  | 
 | ||||||
|  | 1.3.0: Jan 2016: Marinetti 3.0b8 installed, with preconfigured MacIP | ||||||
|  | [unannounced] | ||||||
|  | 
 | ||||||
|  | 1.3.1: Jan 2016: patch Prodos 8 Thunderclock year table based on current date | ||||||
|  | [unannounced] | ||||||
|  | 
 | ||||||
|  | 1.3.2: Jan 2016: install SAFE2, SAM2, and SNAP, configured for Apple II sites; | ||||||
|  | [unannounced]    -i installer option reinstalls A2SERVER | ||||||
|  | 
 | ||||||
|  | 1.5.0: Jan 2016: defaults to GitHub for location of installer scripts | ||||||
|  | [unannounced] | ||||||
|  | 
 | ||||||
|  | 1.5.1: May 2016: changed URLs from rawgit.com to raw.githubusercontent.com | ||||||
|  |                  to resolve https problems during install | ||||||
| @@ -1,7 +1,13 @@ | |||||||
| #! /bin/bash | #! /bin/bash | ||||||
| # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: | # vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh: | ||||||
|  |  | ||||||
| currentVersion=127 | # Ensure URL we'll use ends in a / | ||||||
|  | case "$A2SERVER_SCRIPT_URL" in | ||||||
|  | 	*/) scriptURL="$A2SERVER_SCRIPT_URL" ;; | ||||||
|  | 	*) scriptURL="${A2SERVER_SCRIPT_URL:-https://raw.githubusercontent.com/RasppleII/a2server/current}/" ;; | ||||||
|  | esac | ||||||
|  |  | ||||||
|  | currentVersion=$(wget -qO- "${scriptURL}setup/index.txt" | grep '^a2serverVersion' | cut -d '"' -f 2) | ||||||
|  |  | ||||||
| if [[ -f /usr/local/etc/A2SERVER-version ]]; then | if [[ -f /usr/local/etc/A2SERVER-version ]]; then | ||||||
|     installedVersion=$(cat /usr/local/etc/A2SERVER-version) |     installedVersion=$(cat /usr/local/etc/A2SERVER-version) | ||||||
| @@ -9,12 +15,6 @@ else | |||||||
|     installedVersion=100 |     installedVersion=100 | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # Ensure URL we'll use ends in a / |  | ||||||
| case "$A2SERVER_SCRIPT_URL" in |  | ||||||
| 	*/) scriptURL="$A2SERVER_SCRIPT_URL" ;; |  | ||||||
| 	*) scriptURL="${A2SERVER_SCRIPT_URL:-http://appleii.ivanx.com/a2server}/" ;; |  | ||||||
| esac |  | ||||||
|  |  | ||||||
| autoAnswerYes= | autoAnswerYes= | ||||||
| for arg in $@; do | for arg in $@; do | ||||||
|     if [[ $arg == "-y" ]]; then |     if [[ $arg == "-y" ]]; then | ||||||
| @@ -37,9 +37,8 @@ else | |||||||
|     read |     read | ||||||
| fi | fi | ||||||
| if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then | if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then | ||||||
|     sudo rm /usr/local/etc/A2SERVER-version &> /dev/null |  | ||||||
|     # sudo rm /usr/local/etc/netatalk/a2boot/* &> /dev/null |     # sudo rm /usr/local/etc/netatalk/a2boot/* &> /dev/null | ||||||
|     wget -q -O /tmp/setup "${scriptURL}setup"; source /tmp/setup "$@" |     wget -q -O /tmp/setup "${scriptURL}setup/index.txt"; source /tmp/setup -i "$@" | ||||||
| fi | fi | ||||||
|  |  | ||||||
| unset currentVersion 2> /dev/null | unset currentVersion 2> /dev/null | ||||||
|   | |||||||
| @@ -48,34 +48,32 @@ | |||||||
|  |  | ||||||
| 1.2.3: May 2015: changed Apple software links to Internet Archive | 1.2.3: May 2015: changed Apple software links to Internet Archive | ||||||
|  |  | ||||||
| 1.2.4: Jul 2015: offer to download A2CLOUD disk contents onto A2FILES volume | 1.2.4: Jul 2015: install option for ProTERM, Z.Link, ADTPro, Spectrum images | ||||||
|  |  | ||||||
| 1.2.4+:Oct 2015: support for using A2SERVER scripts from a location other than | 1.2.5: Nov 2015: netboot install option for GS/OS 6.0.2/3; install HFS.FST | ||||||
|                  appleii.ivanx.com/a2server for development purposes |                  during netboot install | ||||||
|                  [not released] |  | ||||||
|  |  | ||||||
| 1.2.5: Nov 2015: netboot install option for GS/OS 6.0.2/3 | 1.2.6: Nov 2015: full, ready to use install of Spectrum | ||||||
|                  netboot always downloads GS/OS disk images even if present |                  [unannounced; released briefly, then withdrawn] | ||||||
|                  provides error if a2setup doesn't have internet |  | ||||||
|                  remove persisting a2server-setup options after aborted install |  | ||||||
|                  fixed installer bug that omits first and last script elements |  | ||||||
|                  download images from Apple, with Internet Archive as a backup |  | ||||||
|                  install HFS.FST during netboot install |  | ||||||
|  |  | ||||||
| 1.2.5+:Nov 2015: Merged Ivan's 1.2.5 release, removed support for Ubuntu for | 1.5.0: Jan 2016: mixed case filenames for A2FILES; remove GSFILES if empty; | ||||||
|                  now (see RasppleII/a2server#11), patched ProDOS 8 in boot |                  install Marinetti 3.0b8 with internet access via MacIP; | ||||||
|                  files for current year table, install unar from a package if |                  fully install Spectrum, SAFE2, SAM2, SNAP, MountIt; install | ||||||
|                  it exists. |                  DOS3.3 and TEACH; remove Ubuntu support; move/media/A2SHARED/* | ||||||
|                  [not released] |                  to /srv/A2SERVER; faster install (precompiled binaries) on | ||||||
|  |                  64-bit Debian; cppo supports ShrinkIt, DOS 3.3, DSK, 2MG,mixed | ||||||
|  |                  case filenames; nulib2 handles empty forks (thanks Andy); | ||||||
|  |                  new installer options; patch P8 Thunderclock driver year table | ||||||
|  |                  for current date; install from any host URL for development; | ||||||
|  |                  source code at GitHub (thanks Joseph) | ||||||
|  |  | ||||||
| 1.2.6: Nov 2015: full, ready to use install of Spectrum; install unzip | 1.5.0r2: Jan 16: fixed GitHub URLs to prevent https errors during installation | ||||||
|                  [released briefly, then withdrawn] |                  (thanks to http://blogs.yahoo.co.jp/ushi_cow/57459736.html) | ||||||
|  |  | ||||||
| 1.2.6+:Nov 2015: merged Ivan's 1.2.6 | Big thanks to: Anthony Martino, Henry Courbis, Joseph Carter, Jason King, | ||||||
|                  [not released] | Andy McFadden, Steven Hirsch, Geoff Body, Peter Wong, Tony Diaz, David Schmidt, | ||||||
|  | David Schmenk, Ewen Wannop, Andrew Roughan, Antoine Vignau, Martin Haye, | ||||||
| 1.2.7: Dec 2015: codebase unified; preliminary Jessie support; case insensitive | Ken Gagne, Peter Neubauer, James Littlejohn, Ninjaforce; the creators of | ||||||
|                  file system for A2FILES; removes GSFILES if empty; DOS3.3.FST | Netatalk, The Unarchiver, ciopfs, macipgw; and the entire Apple II community. | ||||||
|                  and TEACH are installed with netboot installation; minor bug | Redistribution of Spectrum, SAFE2, SAM2, SNAP by permission of Ewen Wannop. | ||||||
|                  fixes and tweaks | Thanks for using A2SERVER! | ||||||
|                  [not released] |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user