Merge pull request #5 from RasppleII/ivanx-docs

Add a lot of documentation from Ivan's website
This commit is contained in:
Joseph Carter 2015-10-23 17:39:26 -07:00
commit f256b9a885
35 changed files with 5195 additions and 0 deletions

19
docs/ivanx/README.md Normal file
View File

@ -0,0 +1,19 @@
# 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.

View File

@ -0,0 +1,38 @@
## 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 \\\\ in an Explorer window.)
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/

View File

@ -0,0 +1,128 @@
## 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

View File

@ -0,0 +1,84 @@
## 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

View File

@ -0,0 +1,64 @@
## 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`.
<a name="wsdisks" />
_Workstation Software:_
<!--
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)

View File

@ -0,0 +1,48 @@
## 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:
`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

View File

@ -0,0 +1,58 @@
## 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:
```
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

122
docs/ivanx/a2server_lan.md Normal file
View File

@ -0,0 +1,122 @@
## 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

View File

@ -0,0 +1,48 @@
## 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:
```
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).

View File

@ -0,0 +1,68 @@
## 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/download

View File

@ -0,0 +1,63 @@
## 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:
`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/

View File

@ -0,0 +1,55 @@
## 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

View File

@ -0,0 +1,108 @@
## 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:
```
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:
```
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/

View File

@ -0,0 +1,123 @@
## 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

View File

@ -0,0 +1,234 @@
## 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!

View File

@ -0,0 +1,44 @@
## 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

View File

@ -0,0 +1,74 @@
## 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

114
docs/ivanx/fix/index.txt Normal file
View File

@ -0,0 +1,114 @@
#!/bin/bash
echo
echo "A2SERVER fix: This utility will make a Raspberry Pi SD card boot if it"
echo "kernel panics (crashes) on startup after updating its operating system"
echo "while A2SERVER is installed."
echo
echo -n "Continue? "
read
doFix=
if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then
while true; do
echo
echo "If attached, remove the Raspberry Pi's SD card from this computer."
echo -n "Press return to continue..."; read; echo
ls -1 /dev/sd? > /tmp/sd1 2> /dev/null
echo "Insert the Raspberry Pi's SD card into this computer, using a USB"
echo "reader if you don't have an SD slot. If this is a virtual machine,"
echo "make sure you select the reader or SD slot from its USB menu."
echo -n "Press return to continue..."; read; echo
ls -1 /dev/sd? > /tmp/sd2 2> /dev/null
# if exactly one drive has been inserted, exit loop
if { ! diff /tmp/sd1 /tmp/sd2 &> /dev/null; }; then
# files are different, get dev name
if [[ $(wc -c /tmp/sd1 | cut -f 1 -d ' ') -eq 0 ]]; then
if [[ $(wc -l /tmp/sd2 | cut -f 1 -d ' ') -eq 1 ]]; then
devName=$(cat /tmp/sd2)
break
else
echo "More than one volume seems to have appeared. Trying again..."
echo
fi
else
devName=$(grep -v "$(cat /tmp/sd1)" /tmp/sd2)
if [[ $(wc -l <<< $devName) -eq 1 ]]; then
break
else
echo "More than one volume seems to have appeared. Trying again..."
echo
fi
fi
else
echo "No SD card found. Trying again..."
echo
fi
done
mkdir -p /tmp/sd
sudo mount ${devName}6 /tmp/sd
raspbianDate=$(date -d "$(zcat /tmp/sd/usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | grep -m 1 ' --' | rev | cut -f 1-6 -d ' ' | rev)" +%s)
doFix=
if [[ $raspbianDate -lt 1403204265 ]]; then
echo "This doesn't appear to be a version of Raspbian that requires fixing."
echo -n "Are you sure you want to continue? "
read
if [[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]]; then
doFix=1
fi
else
doFix=1
fi
if [[ $doFix ]]; then
while read kernelRelease; do
kernelReplaced=
kernelMajorRelease=$(cut -d '.' -f 1 <<< $kernelRelease)
kernelMinorRelease=$(cut -d '.' -f 2 <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/')
kernelPatchRelease=$(cut -d '.' -f 3- <<< $kernelRelease | sed 's/\(^[0-9]*\)[^0-9].*$/\1/')
# if kernel 3.12 below 3.12.25+, delete defective AppleTalk kernel
if [[ $kernelMajorRelease -eq 3 && $kernelMinorRelease -eq 12 && $kernelPatchRelease -lt 25 ]]; then
if [[ -f /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko ]]; then
if [[ $(sha1sum /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk/appletalk.ko | cut -f 1 -d ' ') != "ecb239fc084c36de93f6926e7749b80f6024f269" ]]; then
echo "Removing defective AppleTalk module from kernel $kernelRelease..."
sudo rm -rf /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk 2> /dev/null
wget -qO /tmp/appletalk.ko.gz appleii.ivanx.com/a2server/files/appletalk-$kernelRelease.ko.gz
if [[ $? -eq 0 ]]; then
# if we found a prebuilt one on a2server site, so install it
gunzip -f /tmp/appletalk.ko.gz
sudo mkdir -p /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk
sudo mv /tmp/appletalk.ko /tmp/sd/lib/modules/$kernelRelease/kernel/net/appletalk
echo "Installed fixed AppleTalk module for kernel $kernelRelease."
kernelReplaced=1
fi
fi
fi
fi
done <<< "$(ls -1 /tmp/sd/lib/modules | sort -V)"
sudo umount /tmp/sd
echo kern:$kernelReplaced
if [[ $kernelReplaced ]]; then
echo
echo "All set. Remove your SD card, put it back in your Pi, and boot it."
echo
echo "You should be able to connect from your Apple II, but if you can't,"
echo "log in to your Pi and type 'a2server-setup' to complete the fix."
else
echo
echo "Okey doke. Half done. Remove your SD card, and put it back in your Pi."
echo "After it boots, log in and type 'a2server-setup' to complete the fix."
fi
echo "See the A2SERVER web site at http://ivanx.com/a2server for more help."
echo "(You can type 'sudo shutdown -h now' if you're done on this machine.)"
echo
fi
fi
rm fix &> /dev/null

92
docs/ivanx/index.md Normal file
View File

@ -0,0 +1,92 @@
## 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)
<a name="a2server_next_steps" />
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

View File

@ -0,0 +1,19 @@
#!/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

View File

@ -0,0 +1,126 @@
#!/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

View File

@ -0,0 +1,415 @@
#!/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

View File

@ -0,0 +1,444 @@
#!/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

View File

@ -0,0 +1,95 @@
#!/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

View File

@ -0,0 +1,105 @@
#!/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

View File

@ -0,0 +1,86 @@
# 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"
#

View File

@ -0,0 +1,86 @@
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")

View File

@ -0,0 +1,114 @@
#!/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

View File

@ -0,0 +1,498 @@
#!/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

View File

@ -0,0 +1,882 @@
#!/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()

View File

@ -0,0 +1,286 @@
#!/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

View File

@ -0,0 +1,82 @@
#!/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

285
docs/ivanx/setup/index.txt Normal file
View File

@ -0,0 +1,285 @@
# 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

View File

@ -0,0 +1,37 @@
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

View File

@ -0,0 +1,51 @@
1.0.0: Jan 2012: initial release
1.0.1: Jan 2012: fixes Netatalk date-stamp bug (thanks to Steven Hirsch)
1.0.2: Jan 2013: Netatalk 2.2.4; OS X 10.7+ login fixed; netboot fixes;
Raspbian "Wheezy" support; Ubuntu 12.04 LTS support
1.1.0: Apr 2013: Full GS/OS install; eliminated GS.SYSTEM volume;
Raspberry Pi enhancements; lots of improvements to installer;
more utilities installed for Apple II; improved cppo
NOTE: fresh install required, can't update earlier version
1.1.1: Jun 2013: Wi-Fi support; updates/additions to commands in a2server-help;
bug fixes and improvements to install script; appletalk kernel
module for Raspbian (instead of replacement kernel); RPi
console (onboard serial) set to 19,200 bps during boot
1.1.2: Oct 2013: resolves issue of no AppleTalk in Raspbian 2013-09-10 and
later; faster command-line installation on Raspberry Pi
(nulib2 and unar binaries are downloaded rather than compiled)
1.1.3: Jan 2014: shares ADTPro disks folder as ADTDISKS; added environment
variables for shared folders; can resolve by name
"a2server.local" if network client has Bonjour/zeroconf;
server presents itself as Shared computer to Macs on network;
VM based on Debian 7
1.1.4: Jan 2014: fixes bug with network boot if ADTPro disks folder is shared
1.1.5: Jul 2014: a2server-setup fixes Raspbian 20-Jul-14 AppleTalk kernel panic
1.2.0: Aug 2014: a2server-setup and Netatalk startup script addresses AppleTalk
kernel panic on any Linux kernel 3.12-3.15; Netatalk starts
in background, preventing startup delay; a2server-setup always
configures Netatalk startup script and can download a new one
if missing; a2server-setup on Raspbian or Debian 7 x86 is
faster because it downloads binaries rather than compiling
from source; unbit/unexec/usq unarchivers added; additional
virtual machine which has both A2SERVER and A2CLOUD installed
1.2.1: Jan 2015: minor fixes; support for LED blink on Raspbian 2015-01-31
1.2.2: Mar 2015: installer improvements: now has command line options,
including unattended install; installer sets passwords
automatically to 'apple2'; status messages are now prefixed by
A2SERVER:; can update Raspple II (Raspbian OS,
NOOBS install manager, A2SERVER, and A2CLOUD); minor fixes.
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