So you wanna run a CP/M network?

Introduction
I. Your First Server
    A. Telneting to the Server
    B. Configuration
II. Your First Client
    A. Running the Server
    B. Running the Client
III. Expanding Your Network
Epilogue
Scripts
    Z80Pack Installation
    Client Installation
    Server Installation
    Enhanced Launch Script

Introduction

CP/M does networks!? Who knew? Well, it does, it's called (perhaps not-too-creatively) CP/Net, and, like the rest of Digital Research's products, it has been freely available for many years. The problem has always been assembling, compiling and installing it.

Well, that used to be a problem. Not anymore. Udo Munk, developer of the best-in-class Z80Pack Z80 emulator, has done all the hard work, making it possible for even the most technically incompetent (speaking from experience) of us to become CP/M network admins in just a few minutes' time. And as an added bonus, through the magic of Z80Pack, you can connect your CP/Net network up to the Internet and access it from anywhere in the world. Not even Gary Kildall could have imagined that!

This tutorial assumes that you are running Linux as your host OS, that you already have Z80Pack installed to ~/z80pack/, and that you have basic familiarity with opening and using a command terminal. If you are running Windows, the differences should be trivial. And if you don't yet have Z80Pack installed, there are easy-to-follow instructions at the site, or you can use our quick installation script to get it done for you.

Ready? Here we go.

Your First Server

In this first part, you're going to install a single CP/Net server and connect to it via telnet. You've got Z80Pack installed, right? Now it's time to install the server. Ready ... set ...

You're done.

Yep, CP/Net is part of the base install of Z80Pack. All we need to do is make one configuration change and then launch our server. Open a terminal window and run the following commands:

$> cd ~/z80pack/cpmsim/conf/
$> ls

You should see two files: net_client.conf.example and net_server.conf.example. We're going to enable the server, so:

$> cp net_server.conf.example net_server.conf

That's it. We're now ready to start the server.

$> cd ~/z80pack/cpmsim
$> ./mpm

Z80Pack will load and launch a CP/M session. Look for messages like console 1 listening on port 4000, telnet = on as Z80Pack starts up. If you see the message bind server socket: Address already in use, make sure you don't have any other mpm sessions currently running.

#######  #####    ###            #####    ###   #     #
     #  #     #  #   #          #     #    #    ##   ##
    #   #     # #     #         #          #    # # # #
   #     #####  #     #  #####   #####     #    #  #  #
  #     #     # #     #               #    #    #     #
 #      #     #  #   #          #     #    #    #     #
#######  #####    ###            #####    ###   #     #

Release 1.35, Copyright (C) 1987-2017 by Udo Munk

CPU speed is unlimited
Server network configuration:
console 1 listening on port 4000, telnet = on
console 2 listening on port 4001, telnet = on
console 3 listening on port 4002, telnet = off
console 4 listening on port 4003, telnet = off

Booting...

64K CP/M Vers. 2.2 (Z80 CBIOS V1.2 for Z80SIM, Copyright 1988-2007 by Udo Munk)

A>

At the CP/M A> prompt, run:

A>MPMLDR

to load the multi-user version of CP/M. And that's it. You can work on the server directly, but the real fun is logging in remotely. Let's do that now.

Telneting to the Server

Open a new terminal window and run:

$> telnet localhost 4000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.


MP/M II V2.0
Copyright (C) 1981, Digital Research

1A>

You should have connected and found yourself at a CP/M prompt (that was easy!).

You can open a second terminal and telnet to port 4001. And for the piece de resistance, with a little port forwarding you can even telnet in to your server from the Internet. What fun!

WARNING! To exit your telnet connections, do not type exit or bye. This will shut down your server, which is probably not what you desired. If you're using the standard Linux telnet client, type ^] to escape to the telnet prompt, then close to close the telnet connection without affecting the server.

$> telnet localhost 4000 Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.


MP/M II V2.0
Copyright (C) 1981, Digital Research

1A>
telnet> close
Connection closed.

Configuration

Your CP/Net server supports up to four connections, but out of the box only two are enabled for telnet. Let's take a look now at the configuration file.

$> cd ~/z80pack/cpmsim/conf/
$> cat net_server.conf

You should see the following:

# Console       telnet flag     TCP/IP port
1               1               4000
2               1               4001
3               0               4002
4               0               4003

This tells us that the four supported consoles are connected to the four TCP/IP ports 4000-4003, and that ports 4000 and 4001 are enabled for telnet access. The second two have telnet disabled and can be used for login by CP/Net clients (more on this, later). Now run:

$> telnet localhost 4001

You should find yourself again connected to your server, only this time the command prompt says, 2A>, indicating you have been assigned user 2.

To connect more telnet sessions, you'll have to enable telnet on the other consoles. Shut down all your client sessions and your server by typing BYE at the server's console. Edit conf/net_server.conf, change the telnet flags to "1", save, exit and then relaunch your server. Now you will be able to telnet to any or all of the ports 4000 - 4003.

If all you wanted was a CP/M session you can remotely connect to, you're done. Enjoy! If you want to learn how to set up and connect a CP/M client, read on.

Your First Client

OK, I admit it. I lied. In the first part above we weren't really running a CP/Net server, just an MP/M machine with telnet-accessible consoles. But it pretty much acts like a server and everything, so why not call it a server?

In this part we're going to be installing a CP/Net client, but it will need a real server to connect to, so we will install one of those as well. But first, if you currently have a server running, shut it down by typing A:BYE.

To kick things off we'll download the client and server packages. So open a terminal and run these commands:

$> cd ~/z80pack/cpmsim/
$> wget https://www.autometer.de/unix4fun/z80pack/ftp/cpm2-net-1.2.tgz
$> wget https://www.autometer.de/unix4fun/z80pack/ftp/mpm2-net-1.2.tgz
$> tar -xvf cpm2-net-1.2.tgz
$> tar -xvf mpm2-net-1.2.tgz
$> ls

You should see two new session launch scripts in ~/z80pack/cpmsim/: cpm2-net2 and mpm-net2. These scripts will require updating before we can run them. We'll use the nano editor here, since it comes with most Linux distros.

$> nano cpm2-net2

Change all instances of, e.g., drivea.cpm to drivea.dsk, then save and exit. Then do the same for mpm-net2.

Running the Server

Now, we will need to enable networking and run the server:

$> cd ~/z80pack/cpmsim/conf/
$> rm *.conf
$> cp net_server.conf.example net_server.conf
$> cd ..
$> ./mpm-net2

You should see the start-up banner for the MP/M server:

console 1 listening on port 4000, telnet = on
console 2 listening on port 4001, telnet = on
console 3 listening on port 4002, telnet = off
console 4 listening on port 4003, telnet = off

Booting...

64K CP/M Vers. 2.2 (Z80 CBIOS V1.2 for Z80SIM, Copyright 1988-2007 by Udo Munk)

A>

If you see the message, bind server socket: Address already in use, check to make sure you didn't forget to shut down your other servers, then try again.

Finally, load MP/M:

A>MPMLDR

You should see lots of stuff, and then the sign-on banner:

MP/M II V2.0
Copyright (C) 1981, Digital Research

0A>

Running the Client

Your server is up and running. On to the client. Since we're going with default settings, we only need to swap network configuration files and start the client. Open a new terminal:

$> cd ~/z80pack/cpmsim/conf/
$> rm *.conf
$> cp net_client.conf.example net_client.conf
$> cd ..
$> ./cpm2-net2

Verify that you saw the message Connecting to localhost at port 4002 and the sign-on banner, 64K CP/M Vers. 2.2 (Z80 CBIOS V1.2 for Z80SIM, Copyright 1988-2007 by Udo Munk) then, at the A> prompt start the network, then log in and map a network resource:

A>CPNETLDR


CP/NET 1.2 Loader
=================

BIOS         FA00H  0600H
BDOS         EC00H  0E00H
SNIOS   SPR  E900H  0300H
NDOS    SPR  DD00H  0C00H
TPA          0000H  DD00H

CP/NET 1.2 loading complete.

A>LOGIN

A>NETWORK B:=B:

A>

Both the LOGIN and NETWORK commands will return silently if successful. If you see the message Login failed, verify that you downloaded the same version of the client and server software, above.

So our server is running, our client is logged in, and we've mapped a network resource. Now it's time to play :) . On the client, run:

A>DIR B:
B: MPM      SYS : RESBDOS  SPR : NETWRKIF ASM : SYSTEM   DAT
B: BNKBDOS  SPR : TMP      SPR : GENSYS    OM : BNKXIOS  MAC
B: MPMSTAT  BRS : SPOOL    RSP : ABORT    RSP : SCHED    RSP
B: BNKXIOS  SPR : HWCLOCK  RSP : RESXIOS  SPR : BNKXDOS  SPR
B: SERVER   RSP : SPOOL    BRS : XDOS     SPR : SCHED    BRS
B: MAIL     COM : M80      COM : SYSGEN   SUB : MPMSTAT  RSP
B: NETWRKIF RSP
A>

Since we've mapped local drive B: to the server's B: drive, we are seeing the contents of B: on the server. Now let's check the network's status:

A>CPNETSTS

CP/NET 1.2 Status
=================
Requester ID = 11H
Network Status Byte = 10H
Disk device status:
  Drive A: = LOCAL
  Drive B: = Drive B: on Network Server ID = 00H
  Drive C: = LOCAL
  Drive D: = LOCAL
  Drive E: = LOCAL
  Drive F: = LOCAL
  Drive G: = LOCAL
  Drive H: = LOCAL
  Drive I: = LOCAL
  Drive J: = LOCAL
  Drive K: = LOCAL
  Drive L: = LOCAL
  Drive M: = LOCAL
  Drive N: = LOCAL
  Drive O: = LOCAL
  Drive P: = LOCAL
Console Device = LOCAL
List Device = LOCAL
A>

There is of course much more to running a CP/Net network. Udo Munk, the author of Z80Pack, has made full documentation available at the Z80Pack website. The two best places to begin are the CP/NET Network Operating System Reference Manual and the MP/M 2 manual.

Expanding Your Network

Yes! This is great and all, but you want more. More servers! More clients! More!

As mentioned above, it is possible to connect up to four clients to a server. But each client must be manually configured to connect to a specific server port.

$> cat conf/net_client.conf.example

# example for network client configuration
#
# Console       host                    TCP/IP port
#1              www.unix4fun.org        4052
1               localhost               4002

As you can see, the default setting for a client hardwires it to port 4002. To connect additional clients, you must manually change the port setting to 4001, etc., before launching the client.

And just by the way, as the configuration file shows us, we could connect our client to a server on the internet, or even to a local network address, allowing CP/Net to piggyback over TCP/IP networks! Cool, no? (Just don't try the example shown; Udo Munk no longer runs that server.)

It is also possible to install multiple servers. But in order to prevent servers from stepping on each other's ports, you must manually configure each server's port assignments in net_server.conf, and make sure each port you wish to connect a client to has telnet disabled.

As you can imagine, all this manual downloading and installation, and constant reconfiguring of port settings and swapping in and out of configuration files can become tedious (not to mention error prone) like real quick. But, hey, I got your back. Nathanael's Super-Duper Client Installation Script (or "NaSuDuClInSc", for short :) ) and Nathanael's Super-Duper Server Installation Script ("NaSuDuSerInSc") are here for you.

Click on each of the links above to see the scripts. Save each script to ~/z80pack/cpmsim/; we'll call ours client_install and server_install. Then chmod +x each one.

First, shut down all clients and servers currently running by type A:BYE in each one. Then since we will no longer be needing the client and server we installed above, let's adios them.

$> cd ~/z80pack/cpmsim
$> rm cpm2-net2
$> rm mpm-net2

Now run the server installation script:

$> ./server_install

The script will download and install the server software, place a network configuration file for it in conf/library/ and then create a session launch script called mpm-server1.

Now run the client installation script twice to create two clients.

$> ./client_install
$> ./client_install

and you will have two session launch scripts called cpm2-client1 and cpm2-client2.

You can run the server and client install scripts repeatedly to install additional servers and clients and they will be assigned sequential names such as mpm-server2, mpm-server3, cpm2-client3, etc. The install and launch session scripts will automatically handle all the configuration stuff; all you need to do is to run the session script when you wish to run a particular server or client.

Note that each client is configured to connect to a specific server, so that if you wish to run a specific client, you should make sure its assigned server is already running. It might be good to look briefly at how these install scripts set things up.

Those familiar with Z80Pack know that it stores virtual disk images in disks/library/ and that a session install script will create links to those images in disks/. Network configuration is handled by the server and client install scripts in the same way: a config file is placed in conf/library/ for each client and server, and that client's or server's session launch script will place a link to it in conf/.

On installation, each server is assigned a range of ports, with the telnet flags enabled for Consoles 1 and 2, disabled for Consoles 3 and 4.

ServerConsole 1 (T)Console 2 (T)Console 3 (-T)Console 4 (-T)
mpm-server14000400140024003
mpm-server24004400540064007
mpm-server34008400940104011
mpm-server44012401340144015

On the client side, each pair of clients is configured to connect as follows:

ClientPortServer
cpm2-client14002mpm-server1
cpm2-client24003mpm-server1
cpm2-client34006mpm-server2
cpm2-client44007mpm-server2
cpm2-client54010mpm-server3
cpm2-client64011mpm-server3
cpm2-client74014mpm-server4
cpm2-client84015mpm-server4

Of course these are just default settings which you are free to change should you want to. Just edit the .conf files in conf/library/.

Now let's run our server and clients:

$> ./mpm-server1

At the A> prompt, load MP/M:

A>mpmldr

Server's up and waiting! Open a second terminal.

$> ./cpm2-client1

Look for a message saying, Connecting to localhost at port 4002. Load CP/Net and login in.

A>cpnetldr


CP/NET 1.2 Loader
=================

BIOS         FA00H  0600H
BDOS         EC00H  0E00H
SNIOS   SPR  E900H  0300H
NDOS    SPR  DD00H  0C00H
TPA          0000H  DD00H

CP/NET 1.2 loading complete.

A>login

A>

Now the second client. In a third terminal do:

$> ./cpm2-client2

This time you should see, Connecting to localhost at port 4003. Again, load CP/Net and login.

Epilogue

Th-th-th-that's all, folks! Through the wonders of Z80Pack, you can set up as simple or complex a CP/Net network as you'd like, and all you have to do is run a couple of scripts and edit a few configuration files.

So what's next? The fun, of course, of learning how to administer a CP/Net network. For that, the Z80Pack website has made full documentation available. Start by reading through the CP/Net Network Operating System manual, the CP/M 2.2 Operating System Manual and the MP/M 2 User's Guide, then explore the wealth of other resources available at the site. To discuss with other CP/M afficianados, head on over to the very active comp.os.cpm. And to download CP/M software, try my own archive, the *HUMONGOUS* CP/M Software Archives.

Scripts

These scripts have only been tested with Bash. For Windows users, they shouldn't be too difficult to convert.

Z80Pack Installation

Save this script to whatever directory you want Z80Pack installed inside of. E.g., if you want Z80Pack to be installed to ~/z80pack-1.36/ then save this script in ~. Then just run it. If there is a more recent version of Z80Pack available, or if for some reason you want to install an older version, then change the zver variable accordingly.

#!/bin/bash

# Variables

  zver=1.36           # Z80Pack version you wish to install; e.g., 1.36
  zroot=$(pwd)        # where to put z80pack-x.yy/; default to current dir
  zloc=$zroot/z80pack-$zver
  osenv=linux         # Your operating environment; one of linux, cygwin, osx, solaris or bsd 
  sharedlib=/usr/lib  # a shared library directory on your system

function zpack {
  echo " ------------------------------ "
  echo "   Installing Z80Pack           "
  echo " ------------------------------ "

# Obtain and unpack Z80Pack
  mkdir -p $zroot
  cd $zroot
  wget https://www.autometer.de/unix4fun/z80pack/ftp/z80pack-$zver.tgz
  tar xvf z80pack-$zver.tgz
  rm z80pack-$zver.tgz
}

function buildit     {
  echo " ------------------------------ "
  echo "   Building $component          "
  echo " ------------------------------ "
  # build it
  cd $zloc/$component/
  [ -d srcsim/ ] && cd srcsim/       # frontpanel has no srcsim/
  make -f Makefile.$osenv
  make -f Makefile.$osenv clean

  # Backup disk images
  if [ -d ../disks ]
   then
    mkdir -p disks/backups
    cp -p disks/library/* disks/backups/
  fi
}

function cromemcosim { 
  component=cromemcosim ; buildit 
  }
  
function imsaisim    { 
  component=imsaisim    ; buildit 
  rm $zloc/webfrontend/civetweb/libcivetweb.a # no longer needed
  }
  
function cpmsim      { 
  component=cpmsim      ; buildit

  # Compile support programs. 
  # Make sure ~/bin is in your search path: export PATH=PATH:~/bin
  mkdir -p ~/bin
  cd $zloc/cpmsim/srctools
  make
  make install
  make clean
}

function frontpanel { 

# sudo apt-get install g++ libjpeg8-dev libglu1-mesa-dev libxmu-dev   
  component=frontpanel ; buildit
  
  echo " ------------------------------ "
  echo "   Enter your admin password:   "
  echo " ------------------------------ "
  sudo cp libfrontpanel.so $sharedlib/
}

function altairsim { component=altairsim ; buildit
  
  # Install additional
  cd $zloc/altairsim/
  for mits in dbl.hex dbl.asm dbl.prn; do
    wget https://www.autometer.de/unix4fun/z80pack/ftp/altair/$mits
   done
  for mits in mits-cpm22.tgz mits-cpm14.tgz mits-basic40.tgz mits-basic50.tgz mits-cpm-tools.tgz mits-cpm-ws30.tgz mits-dos.tgz
   do
    wget https://www.autometer.de/unix4fun/z80pack/ftp/altair/$mits
    tar -xvf $mits
    rm $mits
   done
   
  # Make scripts
  cat > mits-cpm22 <<EOL
#!/bin/sh
#
rm -f disks/drive[abcd].dsk
ln disks/library/mits-cpm22-56k.dsk disks/drivea.dsk
ln disks/library/mits-cpm-tools.dsk disks/drivec.dsk
#
./altairsim -x dbl.hex $*
EOL

  chmod +x mits-cpm22

  cat > mits-cpm14 <<EOL
#!/bin/sh
#
rm -f disks/drive[abcd].dsk
ln disks/library/mits-cpm14-24k.dsk disks/drivea.dsk
ln disks/library/mits-cpm-tools.dsk disks/drivec.dsk
#
./altairsim -x dbl.hex $*
EOL

  chmod +x mits-cpm14


  cat > mits-dos <<EOL
#!/bin/sh
#
rm -f disks/drive[a].dsk
ln disks/library/mits-dos.dsk disks/drivea.dsk
#
./altairsim -x dbl.hex $*
EOL

  chmod +x mits-dos

}

function webfrontend {
  echo " ------------------------------ "
  echo "   Building webfrontend         "
  echo " ------------------------------ "
  cd $zloc/webfrontend/civetweb/
  make -f Makefile
  cp libcivetweb.a $zloc      # required by imsaisim
  make -f Makefile clean      # build so preserve it
  mv $zloc/libcivetweb.a .
}

# --- MAIN ---

zpack
cpmsim
frontpanel
altairsim
cromemcosim
[ -d $zloc/webfrontend/ ] && webfrontend # webfrontend is not in 1.36 or earlier
imsaisim

echo " ------------------------------ "
echo " Z80Pack Installation Complete  "
echo " ------------------------------ "

exit 0

Client Installation

This script installs a CP/M 2.2 client for connecting to an MP/M server. Simply place a copy of the script in your z80pack-x.y/cpmsim/ directory and run it. Run the script once for each client you want. Each client will be named sequentially; e.g. cpm2-client1, cpm2-client2, etc.

For each pair of clients you install you will also need to install a server (see the tutorial above).

#!/bin/bash

# Variables
  zver=1.36 # The latest version of Z80Pack
  zloc=~/cpm/z80pack-$zver
  confdir=conf
  conflib=$confdir/library

# Create dir
  cd $zloc/cpmsim/
  mkdir -p $conflib

# skip existing clients
  clientnum=1
  while [ -f cpm2-client$clientnum ]; do clientnum=$(( $clientnum + 1 )) ;
  done

# Fetch and install
  wget https://www.autometer.de/unix4fun/z80pack/ftp/cpm2-net-1.2.tgz

  # --transform replaces the string 'net2' with 'clientx' in all extracted
  # filenames. Unfortunately, 'client$clientnum' is interpreted literally,
  # so the files first need to be extracted to 'clientx' then renamed.

  tar --transform='flags=r;s|net2|clientx|' -xvf cpm2-net-1.2.tgz
  mv disks/library/cpm2-clientx.dsk disks/library/cpm2-client$clientnum.dsk
  rm cpm2-clientx # We will rebuild this later

# Build configuration files

  # Create network configuration file
  confile=$conflib/cpm2-client$clientnum.conf
  listenport=$((4000 + clientnum*2 - ((clientnum-1) % 2)))

cat > $confile <<EOL
# Network client configuration for Client $clientnum
#
# Console       host                    TCP/IP port
1               localhost               $listenport
EOL

# Build launch script
script=cpm2-client$clientnum

cat > $script <<EOL
#!/bin/bash
#
rm -f disks/drive[a].dsk
ln disks/library/cpm2-client$clientnum.dsk disks/drivea.dsk
#
rm -f $confdir/*.conf
ln $conflib/cpm2-client$clientnum.conf $confdir/net_client.conf
#
./cpmsim $*
EOL

chmod +x $script

#cleanup
  rm cpm2-net-1.2.tgz

Server Installation

This script installs an MP/M 1.2 network server. Simply place a copy of the script in your z80pack-x.y/cpmsim/ directory and run it once for each server you want. Servers will be named sequentially; e.g. mpm-server1, mpm-server2, etc.

For each server, you will probably also want to install some clients (see the tutorial above).

#!/bin/bash

# Variables
  zver=1.36 # The latest version of Z80Pack
  #basedir=~/cpm/z80pack/cpmsim
  confdir=conf
  conflib=$confdir/library

# Create dir
# cd $basedir
  mkdir -p $conflib

# skip existing servers
  servernum=1
  while [ -f mpm-server$servernum ]; do servernum=$(( $servernum + 1 )) ; done

# Fetch and install; rename extracted files
  wget https://www.autometer.de/unix4fun/z80pack/ftp/mpm-net-1.2.tgz

  # --transform replaces the string 'net2' with 'serverx' in all extracted
  # filenames. Unfortunately, 'server$servernum' is interpreted literally,
  # so the files first need to be extracted to 'serverx' then renamed.

  tar --transform='flags=r;s|net2|serverx|' -xvf mpm-net-1.2.tgz
  mv disks/library/mpm-serverx-1.dsk disks/library/mpm-server$servernum-1.dsk
  mv disks/library/mpm-serverx-2.dsk disks/library/mpm-server$servernum-2.dsk
  rm mpm-serverx # We will rebuild this later
  
# Build configuration files

  # Create network configuration file
  confile=$conflib/mpm-server$servernum.conf
  baseport=$(( 4000 + (servernum-1)*4))

cat > $confile <<EOL
# Network server configuration for MP/M Server $servernum
#
# console:      # of the console port, 1-4
# telnet flag:  1 = telnet option negotiation on, 0 = off
# TCP/IP port:  every console needs a different port; every server a unique range
#
# Console       telnet flag     TCP/IP port
1               1               $((baseport+0))
2               1               $((baseport+1))
3               0               $((baseport+2))
4               0               $((baseport+3))
EOL

# Build launch script
  script=mpm-server$servernum

cat > $script <<EOL
#!/bin/sh
#
rm -f disks/drive[ab].dsk
ln disks/library/mpm-server$servernum-1.dsk disks/drivea.dsk
ln disks/library/mpm-server$servernum-2.dsk disks/driveb.dsk
#
rm -f $confdir/*.conf
ln $conflib/mpm-server$servernum.conf $confdir/net_server.conf
#
./cpmsim $*
EOL

chmod +x $script

#cleanup
  rm mpm-net-1.2.tgz

Enhanced Launch Script

If you're running the TMUX terminal multiplexor, here is an enhanced launch script that provides a number of enhanced control options to override disk mountings and network configurations. Simply run the script with the --help parameter for an explanation.

To use the script, simply copy the contents of original launch script into this script and you're set. For example, the stock cpm3 script looks like this:

#!/bin/bash

rm -f disks/drive[ab].dsk
ln disks/library/cpm3-1.dsk disks/drivea.dsk
ln disks/library/cpm3-2.dsk disks/driveb.dsk

./cpmsim $*

Just copy the lines between (but not including) #!/bin/sh and ./cpmsim $*. The example script here already has the lines from cpm3.

When you run the enhanced launch script it will launch the session in a new TMUX window and then automatically attach to that window. You may detach from that session in the usual TMUX way and the session will continue to run detached.

#!/bin/bash

# --------------------------------------------
# copy the original script's lines here:
# --------------------------------------------

  rm -f disks/drive[ab].dsk
  ln disks/library/cpm3-1.dsk disks/drivea.dsk
  ln disks/library/cpm3-2.dsk disks/driveb.dsk

# --------------------------------------------

setdrive () {
  echo "Setting drive $1 to $2"
  
  # Does the specified file exist
  if [ ! -f "$2" ]; then
    echo "Specified disk image $2 cannot be found. Run $0 --help for help."
    exit 1
  fi
  
  # Is there already a link
  if [ -f disks/drive$1.dsk ] ; then
      echo "Removing disks/drive$1.dsk..."
      rm disks/drive$1.dsk || { echo "Unable to remove disks/drive$1.dsk. Make sure it is not write-protected." ; exit 1 ; }
  fi
  
  # Create the link
  ln "$2" disks/drive$1.dsk
  return 0
}

netcfg () { # }
  echo "Setting network configuration file to $2"
  
  # Does the specified file exist
  if [ ! -f "$2" ]; then
    echo "Specified configuration file $2 cannot be found. Run $0 --help for help."
    exit 1
  fi
  
  # Is there already a link
  if [ -f conf/*.conf ] ; then
      echo "Removing current network configuration..."
      rm conf/*.conf || { echo "Unable to remove conf/*.conf. Make sure they are not write-protected." ; exit 1 ; }
  fi
  
  # Create the link
  [[ "$1" == "s" ]] && ln "$2" conf/net_server.conf
  [[ "$1" == "c" ]] && ln "$2" conf/net_client.conf
  return 0
}

showhelp () {
  echo " Z80Pack launch script for $(basename -- $0)                                  "
  echo " --------------------                                                         "
  echo " Parameters:                                                                  "
  echo " --da --db --dc --dd Specify a disk image for a drive; overrides script       "
  echo " --di --dj --dp      settings.                                                "
  echo "                                                                              "
  echo " --ns --nc           Specify the network server or network client configura-  "
  echo "                     tion file.                                               "
  echo "                                                                              "
  echo " -d                  Specify the directory where your disk images are stored. "
  echo "                                                                              "
  echo " --------------------                                                         "
  echo " Examples:                                                                    "
  echo "                                                                              "
  echo " $(basename -- $0) --dc disks/library/tools.dsk                               "
  echo "                     Mount tools.dsk as drive C instead of any image specified"
  echo "                     in the script.                                           "
  echo "                                                                              "
  echo " $(basename -- $0) --ns conf/library/fullserver.conf                          "
  echo "                     Use fullserver.conf as the network server configuration  "
  echo "                     file; overrides settings in the script.                  "
  echo "                                                                              "
  echo " $(basename -- $0) --nc conf/library/newclient.conf                           "
  echo "                     Use newclient.conf as the network client configuration   "
  echo "                     file.                                                    "
  echo "                                                                              "
  echo " $(basename -- $0) -d ~/cpm/imgs                                              "
  echo "                     Load disk images from ~/cpm/imgs instead of the default  "
  echo "                     location. Z80Pack looks for files named drivea.dsk, etc. "
  echo "                                                                              "
  echo " --------------------                                                         "
  echo " Notes:                                                                       "
  echo " Usual disk images and network config files should be set in this script. Use "
  echo " command line parameters for a one-time override.                             "
  echo "                                                                              "
  echo " Z80Pack cannot run with both a server and client network configuration. If   "
  echo " you specify both on the command line, the last one will override earlier     "
  echo " settings.                                                                    "
}

# Repeat until there are no parameters left
while [ "$1" != "" ] 
  do
    case $1 in
      -drivea | --da)
        setdrive "a" "$2"
        shift 2
        ;;
      -driveb | --db)
        setdrive "b" "$2"
        shift 2
        ;;
      -drivec | --dc)
        setdrive "c" "$2"
        shift 2
        ;;
      -drived | --dd)
        setdrive "d" "$2"
        shift 2
        ;;
      -drivei | --di)
        setdrive "i" "$2"
        shift 2
        ;;
      -drivej | --dj)
        setdrive "j" "$2"
        shift 2
        ;;
      -drivep | --dp)
        setdrive "p" "$2"
        shift 2
        ;;
      -netsrvr | --ns)
        netcfg "s" "$2"
        shift 2
        ;;
      -netclnt | --nc)
        netcfg "c" "$2"
        shift 2
        ;;
      --help | -h) 
        showhelp
        exit
        ;;
      *)
        echo "Unrecognized parameter: $1. Try '$0 --help' for help."
        exit 1
        ;;
    esac
  done

# If a tmux session with the same name as this script file does not
# exist, create it and run Z80Pack in it.

x=$(basename -- $0)
tmux has-session -t $x 2>/dev/null
if [ "$?" -eq 1 ] ; then
  echo Starting $x. Attach with: tmux attach -t $x.
  tmux new-session -d -s $x
  tmux send-keys -t $x "./cpmsim $*" C-m
  sleep 2
  # Any start up commands you want to feed to CP/M
  tmux send-keys -t $x "CLS" C-m
  tmux send-keys -t $x "DIR" C-m
fi

# Attach to the tmux session

tmux attach -t $x