Solaris Jumpstart on OSX

Local copy MGO 5-Oct-2005

The information presented here is based on MacOS 10.3.9 and the 10/01 release of Solaris 8. It works for me, but your mileage may vary. If you find this information helpful, or have suggestions to improve the procedure, please drop me a line: osXjumpstart@marget.com

In this walkthrough I'm installing the jumstart tree on /Volumes/Jumpstart. My Solaris distribution media (well, images of same) are mounted on /Volumes/SOL_8_1001_SPARC and /Volumes/SOL_8_1001_SPARC_2. I'm installing a host named jumpclient. Substitute paths and hostnames as appropriate for your environment

1.) Create a Jumpstart Network Location

Your Mac needs to be on a network with a consistent configuration in order for jumpstart to work. I'm using a PowerBook, and will be doing most of my jumpstarting Solarix boxen with just my PowerBook and a network cable, so I need to define a "location" to be used when I'm jumpstarting. If you're working with a servers that don't move around much, then you can probably skip this step.

	Click Apple Menu -> Location -> Network Preferences
	Click Location -> New Location
	Name of your new location: Jumpstart (OK)
	Show: Built-in Ethernet
	Click the TCP/IP tab
		Configure IPv4: Manually
		IP Address: 192.168.100.1
		SubnetMask: 255.255.255.0
		Router: 192.168.100.254
			(Apply Now)
	Quit System Preferences

Now, I know it doesn't seem like it should matter, but the router entry is important. It must be present. With no default route, OSX bootparamd will put 255.255.255.255 in the router field in the responses to WHOAMI requests. The jumpstart will fail. The router doesn't need to exist, but the configuration must be present, and the router must be in the same network as the jumpstart client.

Finally, enter the IP address you've just selected into the hosts file, because add_install_client will look for it there.

	$ cat /etc/hosts > /tmp/hosts
	$ echo 192.168.100.1 osx_jumpstart_server >> /tmp/hosts
	$ sudo mv /tmp/hosts /etc/hosts
	$ sudo chown root:admin /etc/hosts

2.) Prepare The Jumpstart Filesystem

The gotcha with the Solaris jumpstart tree is that it cannot be installed on an HFS filesystem. Unless you've rebuilt your Mac using UFS, you've probably got an HFS filesystem. Not sure which you've got? Try this in the filesystem where you'd like your jumpstart files to live:

	$ touch foo
	$ touch FOO
	$ ls | grep -i foo

If ls finds both the uppercase and lowercase files, you're okay, and can skip section 2. If ls only returns foo, then you're probably using HFS, and need to jump through the rest of these hoops.

Update: I had previously advised creating the filesystem with a combination of mkfile and the Disk Utility application. Thankfully, Alex Koralewski swooped in to offer this much more elegant solution:

	$ hdiutil create -size 1.2g /jump.dmg -type UDIF -fs UFS -volname "Jumpstart" -attach

The size is arbitrary, but the file needs to be at least about this size. There's an incompatibility in the setup_install_server script. It checks for adequate space by comparing the disk blocks reported by /usr/bin/du -s with the KB reported by df, but doesn't realize it's comparing apples and oranges. Rather than fix the script, I just made the file bigger, because I'm sure to dump lots of crap in my jumpstart export later on. This broken space check only happens once.

Update: It turns out that the du vs. df incompatibility was unique to my environment. setup_install_server was finding /sw/bin/du rather than /usr/bin/du. If your du and df -s report the same units, then you should be able to make the image around 650-700MB.

3.) Install the Jumpstart Tree

The Jumpstart tree is installed by the setup_install_server script from the first Solaris CD, and the add_to_install_server script from the second Solaris CD. But it's not quite so simple.

3.1) setup_install_server

3.1.1) The script uses bar for some reason. /usr/bin/tar works fine. Simulate bar with a link from tar.

	$ sudo ln -s /usr/bin/tar /usr/bin/bar

3.1.2) The script uses mach where it should use uname -p. Setup /usr/bin/mach.

	$ echo -e "#\0041/bin/sh\nuname -p" > /tmp/mach
	$ chmod 755 /tmp/mach 
	$ sudo mv /tmp/mach /usr/bin

3.1.3) Empty the jumpstart root

The setup_install_server script checks the target directory to be sure it's empty. Mac OS tends to leave directories named .Trashes everywhere. The script is not expecting this, and doesn't like it. I'm not sure what makes the .Trashes directories reappear, but they do from time to time.

	$ sudo rm -rf /Volumes/Jumpstart/.Trashes

3.1.4) finally, run setup_install_server

The output of setup_install_server isn't going to be pretty. The spinner doesn't print correctly, and there will be some errors along the lines of adb: command not found. Ignore them. Now would be a good time to get some coffee...

	$ cd /Volumes/SOL_8_1001_SPARC/Solaris_8/Tools
	$ sudo ./setup_install_server /Volumes/Jumpstart

3.1.5) Post setup_install_server Cleanup

Now we fix the adb errors. The script was trying to figure out the netmask and stuff it in a file. We'll just do that by hand:

	$ echo 255.255.255.0 | sudo dd of=/Volumes/Jumpstart/Solaris_8/Tools/Boot/netmask

3.2) add_to_install_server

The next step is to run the add_to_install_server script from the second Solaris CD. This script is a bigger problem than the previous one. For one thing, it uses ksh, which isn't available on 10.3.9, so more likely than not, you won't have it. Incidentally, according to http://www.apple.com/macosx/newfeatures/over200.html ksh does ship with 10.4. Alas, 10.4 was still 2 days away when I was solving this problem. There are undoubtedly other incompatibilities with add_to_install_server, but I can't remember what they were. Instead, I gutted the script and did minimal patching to get it to work. I suggest you download my hacked up version and diff it carefully against the one on your Solaris media -- I might have done something stupid. Some of the functionality was lost in the butchering, but it should install the second disk correctly. Be sure to run it from the root of the second Solaris CD, because one of the things I gutted was the bit that determines from where it's being run.

	$ cd /tmp
	$ wget http://logsoft.com/chris/osx_jumpstart/add_to_install_server
	$ chmod 755 ./add_to_install_server
	$ cd /Volumes/SOL_8_1001_SPARC_2
	$ sudo /tmp/add_to_install_server /Volumes/Jumpstart

4.) portmap

/usr/sbin/portmap is needed by several of the other system daemons, namely bootparamd, mountd and nfsd. Start it before starting the others, like this:

	$ sudo /usr/sbin/portmap

5.) bootparamd

bootparamd provides diskless clients with location information for files they need on bootup. It works like this:

the bootparam client queries the server thusly:
"Hi, my name is fooclient, and I'd like to know where to find my file called 'root'"
the bootparam server parses his config files and finds a directive like this:
fooclient swap=swapserver:/path/to/fooclient/swapfile root=rootserver:/path/to/fooclient/rootfile"
having found that entry, the bootparam server responds with:
"Hello, your file 'root' can be found on the server named "rootserver", whose IP address is a.b.c.d. The file is at "/path/to/fooclient/rootfile"

Now, Sun stretches this protocol a little bit. Jumpstart clients use bootparamd to get other kinds of information, Like NFS mount options. A Solaris Jumpstart boot server has this additional directive for each client:

	rootopts=:rsize=32768

Note that the fileserver portion, which should be between the '=' and ':' is missing, and 'rsize=32768' certainly isn't a path to a file.

The MacOS bootparamd will choke on this syntax, but we can make it work. The first step is to define a host with address 0.0.0.0:

	$ sudo nicl / create /machines/blackhole ip_address 0.0.0.0

The second step is to change any bootparams with no host portion. So rootopts=:rsize=32768 becomes rootopts=blackhole:rsize=32768. The modified add_install_client will take care of this.

Now, the bootparam exchange looks like:

client:
"Hi, my name is fooclient, and I'd like to know where to find my file called 'rootopts'"
server:
"Hello, your file 'rootopts' can be found on the server named "blackhole", whose IP address is 0.0.0.0. The file is at "rsize=32768"

That's pretty close to what Solaris bootparamd does. The key differences are that Solaris doesn't return the hostname. That portion of the reply packet is blanked out. Jumpstart clients don't seem to mind seeing a server name here.

One final thing about bootparamd. It doesn't read /etc/bootparams. It pulls parameters from NetInfo. ...But niload, which claims to know how to parse bootparams data, loads the parameters wrong. According to the man page, you should be able to populate /etc/bootparams, and then do this:

	niload bootparams < /etc/bootparams

That pretty much works, with one fatal flaw. It loads the string of bootparams as a single value to the property bootparams in the NetInfo directory /machines/clientname. The correct behavior would be to have many values associated with the property bootparams. For example, if your /etc/bootparams contains:

	client_name root=servername:/path/to/root install=servername:/path/to/install

The way niload reads these values, bootparamd would return an answer to a 'root' query from 'client_name' with: "Hello, client_name, your file 'root' can be found on server 'servername' at location '/path/to/root install=servername:/path/to/install'"

Obviously not what we're looking for. The modified add_install_client will take care of this as well, but I thought it worth mentioning, because it cost me the most time, and because I think it's really broken.

bootparamd caches the route information that it learns from running netstat -r -n. Make sure your location stuff in step 1 is correct before starting bootparamd. Use the -d flag for debugging output.

Start bootparamd:

	$ /usr/sbin/bootparamd

Check for bootparamd in the output of:

	$ rpcinfo -p localhost

6.) tftp

The jumpstart boot server needs to run tftp. I've been running the Mac OS built-in tftpd for a while, so I don't remember exactly what it took to get it going. At a minimum, you'll need to create /tftpboot, and enable the tftp service within xinetd. I think this should do it:

	$ mkdir /tftpboot
	$ sudo /sbin/service tftp start

7.) rarpd

rarpd processes rarp (what is my ip address?) requests from jumpstart clients. It requires:

If all those tests pass, rarpd will send a response to the client, and the client will tftp to the server who answered the rarp query. The setup_install_client script should be taking care of those first 3 requirements. The fourth depends on your MacOS "Jumpstart" network location in step 1.

I run rarpd on interface en0 only. rarpd has seemed unhappy about finding my Airport interface (en1) switched off, and if I switch the Airport on, it will join a network and screw up the default route that's so critical from step 1. If you want to run rarpd on all interfaces, run rarpd -a. For debugging output, use the -d flag.

Start rarpd:

	$ sudo /usr/sbin/rarpd en0

8.) ICMP

Partway through the installation, a Jumpstart client runs the /sbin/get_netmask program while it's setting up its interfaces. This program sends an ICMP type 17 message to the server. By default, your Mac won't answer, and the install will hang with a spinning dial thing forever. The solution is to enable replies:

	$ sudo sysctl -w net.inet.icmp.maskrepl=1

9.) NFS

We need to export the Jumpstart directory to the client. Here's how:

sudo nicl / create /exports/\\/Volumes\\/Jumpstart opts maproot=root:wheel,ro,alldirs

9.1) Messy double-escaped forward slashes.

NetInfo uses forward slashes to delimit the NetInfo hierarchy, and so does the filesystem. So we have to escape (with a backslash) the forward slashes that are part of our file path. The forward slashes on either side of 'exports' are not part of our file path, so they're not escaped. Making matters more complicated, the shell will interpret the backslashes, so we need to put an extra set in there. The first backslash (of each pair) tells the shell to leave the second one alone, and the second tells nicl that the following forward slash is not to be interpreted as part of the NetInfo hierarchy.

9.2) Mount options

The options here are important:

9.3)

The clients directive tells mountd what client systems should be allowed to mount the filesystem. If no clients are specified, then all clients are presumed welcome. My modified add_install_client script will explicitly declare each client, thus implicitly denying all others. I had intended to do this, but haven't yet. If you wanted to add another client, you'd do:
	$ sudo nicl / append /exports/\\/Volumes\\/Jumpstart clients nfs_client_name

9.4) Check out your export directives:

	$ nicl / cat /exports/\\/Volumes\\/Jumpstart
	name: /Volumes/Jumpstart
	opts: maproot=root:wheel,ro,alldirs
	clients: clientA clientB clientC jumpclient clientD

Make sure the name field points exactly to the top of your Jumpstart tree, and that the options look good. You may or may not see the clients: line, depending on what you've done so far.

9.5) nfsd and mountd

Now that the export is fully defined, we can (re)start nfsd and mountd. Having the declarations in NetInfo may cause the daemons to come up automagically on boot. I haven't bothered to reboot to test.

If mountd and nfsd are already running:

	$ sudo kill -1 `cat /var/run/mountd.pid `
if nfsd and mountd are not running:
	$ sudo /sbin/nfsd -t -u -n 6
	$ sudo /usr/sbin/mountd
Check for nfsd and mountd in the output of:
	$ rpcinfo -p localhost

10.) Regular Jumpstart stuff

From here on out, it's regular jumpstart stuff: sysid stuff, rules stuff, etc... I haven't yet ported the check script to MacOS. I usually just create that by hand.

You'll need my modified add_install_client script. Understand that I provide no warranty or support, then get it here: add_install_client

	$ cd /Volumes/Jumpstart/Solaris_8/Tools
	$ mv add_install_client add_install_client.orig
	$ wget http://logsoft.com/chris/osx_jumpstart/add_install_client

Finally, we're ready to set things up a new jumpstart client. I will call him jumpclient

	$ sudo nicl / create /machines/jumpclient ip_address 192.168.100.15
	$ sudo ./add_install_client -c 192.168.100.1:/Volumes/Jumpstart \
		-p 192.168.100.1:/Volumes/Jumpstart/sysidcfg.d/core\
		-e 8:0:20:fa:72:4c jumpclient sun4u

11.) Mac specific stuff

11.1) Serial ports

I use a USB->Serial port adapter made by iConcepts. It's got the pl2303 chipset from Prolific. It works great, with one exception: the rs-232 BREAK signal doesn't seem to be implemented by the driver. This is a real bummer if you're trying to use it to install Sun boxes. Well, it turns out there's a way around this problem. A BREAK signal involves setting voltage on the serial TX line, and holding it there way too long. We can accomplish the same thing by sending ASCII '0x00' (NUL) at a way too-low baudrate.

Dave Alverson's wonderful ZTerm application for OSX includes this functionality built right in. To enable it, simply:

	$ defaults write com.mac.dalverson.ZTerm breakSim '300'

Thanks to Duane Grant for turning me on to ZTerm and the BREAK via baudrate-switcheroo.

11.2) Firewall

All of this can certainly be made to run with the firewall enabled. I have not bothered to try it because my jumpstarting usually involves my PowerBook, a crossover cable, and a blank Sparc. Not much risk of being attacked. Disable the firewall.