Files
opencode.energia.arti.ee 3a56de7757 Add all-in-one IRIX network install server
Provide BOOTP, TFTP (including SGI boot-tape TPD members) and the BSD
rsh/rcmd service that IRIX inst needs. Map exec /bin/sh to mksh or dash
and run the shell in a read-only bubblewrap sandbox with an
IRIX-compatible dd wrapper. Add protocol tests and a usage guide.
2026-11-02 14:39:54 +00:00

5.6 KiB

IRIX network install server

tools/irix_netinstall.py is a single-file BOOTP + TFTP + rsh server for booting the SGI PROM and running the IRIX inst network installer.

It is intended for a dedicated install network. rsh is unauthenticated by design.

Requirements

  • Linux with Python 3.10 or newer.
  • mksh or dash (the server prefers mksh).
  • bubblewrap for the read-only shell sandbox (recommended; --sandbox none runs without it, but then absolute paths can reach the host filesystem).
  • Root, or the ability to bind UDP 67, UDP 69 and TCP 514.
  • No other BOOTP/TFTP/rsh service on those ports.

On Debian/Ubuntu:

sudo apt-get install mksh bubblewrap

Install tree

The server serves an already-extracted IRIX distribution tree. It does not mount ISO images or unpack tardist files itself. The paths used by the PROM and inst are relative to --root:

/srv/irix/
  6.5.30/
    stand/
      fx.ARCS
      fx.64
      sashARCS
      sash64
    dist/
      ...
  install.cmds

The dist directory is what inst opens as the remote distribution. The stand directory is what the PROM boots with bootp().

Run it

sudo ./tools/irix_netinstall.py \
    --root /srv/irix \
    --server-ip 10.0.0.1 \
    --client-ip 10.0.0.2 \
    --client-mac 08:00:69:07:dc:e0 \
    --bootfile /6.5.30/stand/fx.ARCS

Useful options:

Option Meaning
--l2-iface tap-mess-1000-0 BOOTP over AF_PACKET for MAME/QEMU taps
--shell mksh / --shell dash force a shell
--sandbox bwrap / --sandbox none force a shell sandbox mode
--bootp-port, --tftp-port, --rsh-port non-default ports (testing)
--allow-high-ports accept rsh clients from non-reserved ports (tests only)

At the PROM:

setenv netaddr 10.0.0.2
boot -f bootp():/6.5.30/stand/fx.ARCS

For a 64-bit machine use fx.64; for the 32-bit IP22 Indy/Indigo2 use fx.ARCS.

After partitioning, return to the maintenance menu, choose the software installation option, enter the server address and the distribution path without a trailing slash, for example:

/6.5.30/dist

Then load a command file at Inst>:

admin source 10.0.0.1:/install.cmds

What the services do

BOOTP

Answers RFC 951 requests on UDP 67. The reply carries:

  • yiaddr = --client-ip
  • siaddr = --server-ip
  • file = the file the PROM asked for, or --bootfile
  • the client's chaddr, transaction ID and flags echoed

It can answer by MAC (--client-mac) and accepts plain UDP or AF_PACKET (--l2-iface). The L2 mode exists because some emulated clients send from 0.0.0.0 in a way the host IP stack never receives.

TFTP

Serves RFC 1350 RRQ in octet mode. It opens a new UDP socket per transfer and keeps that socket's source port at or below 32767, because the 5.0 B6 and 5.1.2 B4 PROMs compare the server port as a signed 16-bit value.

It also supports the SGI boot-tape directory format:

bootp():/images/boottape(sash)

The first 512-byte block is checked for magic 0xACED1234 (or the byte-swapped 0x3412EDAC), the checksum, and the 20-entry directory; only the requested member's bytes are transferred.

rsh

Serves the BSD rcmd protocol on TCP 514:

  • the client must connect from a reserved source port (512-1023);
  • the server reads the stderr port, dials back before reading the user and command fields, then answers with a zero byte;
  • exec /bin/sh is accepted and mapped to mksh, falling back to dash;
  • stdout is the primary connection, stderr is the callback connection;
  • callback bytes 0x02 are forwarded to the shell's process group as SIGINT.

The host's /bin/sh is never changed.

Why mksh/dash, not bash or csh

inst runs exec /bin/sh and streams real POSIX shell lines: dd, cat, ls, grep, pipes, subshells, trap, $?, and the marker idiom:

echo 'TOKEN\c'

Bash's builtin echo does not interpret \c by default (not even with --posix), so the marker gets a literal \c and a newline. csh is a different syntax family entirely and cannot parse the stream.

mksh and dash handle \c correctly. The server prefers mksh because it is the shell used by the proven IRIX install guides.

The shell is run in a read-only bubblewrap sandbox:

  • the install tree is bound at /irix and each top-level entry is symlinked to /, so absolute inst paths such as /6.5.30/dist work;
  • host /bin, /usr, /lib, /lib64 and /etc are bind-mounted read-only;
  • a small wrapper directory provides an IRIX-compatible dd that accepts iseek/oseek and refuses writes;
  • egrep/fgrep wrappers map to GNU grep -E/-F.

With --sandbox none, the shell runs with the install tree as its working directory but can still reach absolute host paths. Use that only on an isolated install network.

Tested

Protocol tests run without root on loopback:

cd tools
python3 -m unittest -v test_irix_netinstall

They cover BOOTP, TFTP file and TPD-member transfers, rsh shell sessions, the \c marker, and dd under both none and bwrap. The server has not yet been run against a physical Indy, so treat a real install as the acceptance test.

Prior art

  • instigator — Go server with BOOTP/TFTP/rsh and a constrained POSIX interpreter; the best reference for the inst shell vocabulary.
  • irixboot — Vagrant VM using isc-dhcp, tftpd-hpa and rsh-server.
  • Remote IRIX 6.5 install from Linux — the mksh + in.rshd + bootp + tftpd recipe.