io man page


io,  iosrv,  ioshell   -  persistent multiplexed i/o sessions, or 'screen without a


io [ -a -i -p -v ] [ -l logfile ] [ -c cmd ] srvname

io srvname [ zap slow fast here ]

iosrv [ -hrspv ] [ -t sleeptime ] srvname

ioshell filefromfd0 filetofd1 filetofd2 ctlfile


Io invokes iosrv(1) to create a system of pipe(3) devices available as  a  srvfs(4)
and starts an rc(1) shell with its file descriptors redirected to these pipes, then
uses ioshell(1) as a client for these connections. The overall usage model is some-
what  similar  to GNU screen but without the additional complexities of TTY manage-

The base behavior of io(1) srvname is bimodal, and will function as either a client
or server depending on whether /srv/srvname exists. If no name is provided, io will
create or attach to a /srv named /srv/iorc.$pid containing a persistent rc session.
Thus, the simplest possible model of use is:


to start a backgrounded iosrv hosted persistent rc shell, and then


from any window with access to that /srv to connect to it.

By  default,  no  connection is made to the initially created rc.  The -a flag will
connect the calling window to the rc by simply invoking io  srvname  after  it  has
completed  the  iosrv  /srv setup. Conversely, if the -i flag is given, the initial
window is run with the iosrv server itself foregrounded in interactive control con-
sole  mode,  with  logging sent to the initiating window and that window's keyboard
input sent to the ctl/data file. Otherwise, the output is backgrounded and  control
messages  can only be written via echo to the mounted ctl/data pipe.  The -v option
activates verbose debug logging of all the client and server message  passing,  and
-l  logfile  redirects logging information in either mode to the specified file, or
to /tmp/iolog$pid if no filename is given.

The -p flag is used to start in 'paranoid' mode. Normally,  reading  processes  may
fill  the  buffers  (sized  to  512k  in  the  default compile) ahead of the output
clients, who catch up 'as fast as they are able'.  Paranoid mode  enforces  a  'one
read  one  write'  behavior.  This  is generally not desirable unless a slow client
needs to request well over 512k data at once at maximum speed.

The -c command option replaces the default backgrounded rc with the command of your

io -c cat

will make cat(1) the active process. Subsequent commands of the form io will
connect to the running backgrounded cat process, allowing for a very  simple  chat-
type application between multiple users. ( chmod 666 /srv/ by the controlling
user will be necessary first.) For more complex commands a certain amount of  inge-
nuity in string quoting may be required.

io  in  its client role accepts no flags. When /srv/srvname exists, io srvname will
mount the /srv and then start an ioshell client attached  to  a  new  set  of  file
descriptors requested from the iosrv.  Multiple clients may connect simultaneously,
and clients may disconnect and reconnect freely. The optional arguments [ zap  fast
slow  here
  ]  are translated into commands sent to the iosrv ctl file.  zap clears
the log prior to connecting.  slow and fast set the basic loop speed of the  server
processes. (Processes lock or block during idle, so this does not affect load, only
maximum throughput and consumption of system resources during constant  i/o  trans-
mission.)  here creates an additional rc on the CLIENT machine attached to the cur-
rent iosrv and attaches to it. In other words, this allows the client  to  share  a
persistent rc session back to the HOST iosrv and its other clients.  An arbitrarily
compiled-in maximum of 64 file descriptors can be used progressively for  a  single

The  ioshell client provides a few features to interface with iosrv.  It is invoked
automatically by io and rarely directly by the user. Fundamentally, ioshell  simply
acts  to  "bucket  brigade" data between the user's existing shell file descriptors
and the pipes managed by iosrv.  The ioshell is basically transparent to input  and
output  with the exception of providing a set of commands and a communication chan-
nel to the iosrv.  Some text strings are intercepted by  the  ioshell  and  trigger
special  actions.  In  particular: remote # , local # , attach # , clear , detach ,
hist , and hub cmdstring are treated as follows. Note that the  connection  context
is relevant in particular for:

remote #

which  creates  a new rc session on the HOST machine (the machine running the iosrv
being targeted) with 3 new Hubs activated and shifts the connection to it. # corre-
sponds to the lowest numbered of the new Hubs. This command can only be issued when
actually connected to an io session on the remote host. (This  corresponds  to  the
conventional creation of a new shell within 'screen'.) Conversely,

local #

functions similarly but the rc is hosted by the CLIENT machine (the machine import-
ing the /srv - if both the client and the server are on the  same  machine,  remote
and  local are equivalent.) Multiple clients can all share rc sessions to the other
clients via the shared iosrv. In other words, starting new shared  rc's  using  the
local  option  makes  iosrv  the  equivalent  of  a  shared  /srv for the connected
machines, where any machine can post new pipes for either  input  or  output.  Note
that  local  will  always  refer  to  the  local client machine, but the meaning of
'remote' shifts depending on where the current ioshell is attached.

attach #

shifts to the currently existing iosrv rc whose lowest Hub # is  given.  Using  new
and attach, the user can create additional instances of rc connected to the current
iosrv and switch between them freely. VERY IMPORTANT: as a  standard  rc  shell  or
other  traditional  textual input/output program uses 3 file descriptors, numbering
should proceed by increments of 3 as additonal rc are attached  to  a  given  iosrv
host.  Some  care must be taken to track these numbers as the results of misaligned
attaches could be disruptive to the integrity of the session. The  simple  rule  is
that  the numeric parameter to the attach, remote, and local commands should always
be a multiple of 3.


ends the current ioshell attachment to the iosrv pipes - it  does  not  affect  the
remote system in any way, it simply returns control to the original shell. (it also
requests a fortune(1) on the way out.)   clear  resets  the  internal  buffers  and
pointers of the primary set of hubs (H0, H1, and H2).  hist provides a command his-
tory of the user's attached ioshell.  Note this  is  not  a  complete  log  of  all
attached  input  clients,  but  only of the local client.  hub cmdstring sends cmd-
string to the iosrv ctl file, enabling arbitrary commands to be passed to the  ses-
sion.  Notable  commands  include: hub fear to active paranoid mode and hub calm to
deactivate it.  hub quit terminates the entire  iosrv  and  kills  all  reader  and
writer  processes.   hub  debug  and hub shutup act to start and stop verbose debug
output respectively. (Note: the logging information is  not  sent  to  the  ioshell
client, but rather to the location specified by the initial io server command.).

The  low  level  hub  commands are also supported. Each hub command begins with the
letter 'h', is followed by a numeric Hub identifier, then a  single  letter  repre-
senting  a  verb,  and  then  usually  an  additional numeric parameter. The io and
ioshell tools use these commands to perform their actions.

hub h1t50

from within an attached ioshell sets the sleeptime parameter of Hub  1  to  50  ms,
which  will  occur  twice per read cycle and at least once per write cycle. See the
examples section and source code for more details. Verbs are:  t: time,  c:  clear,
s:  start,  o:  output.  e: err, i: input, f: freefd, k: killfd x: xit, v: view, y:
kill rdproc, z: kill wrproc. All commands except c, x, and v  take  a  4th  numeric
parameter.  Due  to  ongoing development, a full specification of the 'h%d%c%d' Hub
commands will not be offered in this manpage.

The iosrv command is usually called from the io wrapper script.  The  options  that
vary  from  those  of the wrapper script are mostly experimental debugging options.
The -dhrs flags deactivate the default setup, turn off  file  descriptor  preserva-
tion,  turn  off ramfs(4) and prevent a /srv from being posted, respectively. Check
the source code for details.

In theory, there is nothing preventing the iosrv pipes from carrying  any  kind  of
data.  A  small amount of testing of remote control of GUI apps indicates this is a
fruitful area for experimentation, and in theory multiple iosrv can be connected to
create pipe topologies of arbitrary complexity involving multiple machines with the
ability to connect and disconnect clients in real time.


For most users and purposes, io srvname used to both start and connect to  a  given
/srv  (in  combination with any needed network imports) will be the primary mode of
usage, along with remote # and attach # commands from within the attached ioshells.
The  concluding  example  of  a  manually created set of connections is provided to
demonstrate additional possibilities for  further  development  of  the  underlying
iosrv core.

Start a session named aug1 and connect to it in the same window as it was launched:

io -a aug1

Connect a second client to that session:

io aug1

Start  another session named rc.2 backgrounded but with non-verbose logging written
to the default logfile:

(host) io -l rc.2

Connect to that rc session from a remote client. First, import the  host  machine's
/srv then connect and also clear the backscroll:

(client) import -ac HOST /srv

(client) io rc.2 zap

From  within  that rc, create another rc attached to the current iosrv beginning on
Hub 3 (the first available):

(client io:) remote 3

connect another client and switch to that rc:

(client) io rc.2

(client io:) attach 3

switch back to the original rc:

(client io:) attach 0

share an rc from the client machine back to the iosrv:

(client io:) local 6

from inside a connected HOST machine ioshell connect to the new rc  hosted  by  the

(host io:) attach 6

The  above series of commands demonstrates the basic principle of referring to mul-
tiple rc sessions within a single iosrv is that the numbering proceeds  by  threes,
because  each rc makes use of a set of the three standard file descriptors, each of
which uses one Hub. Leaving Hubs unused in between rc trihub groupings is  harmless
apart  from  inefficiency, but overlapping multiple trihubs within the same numeric
grouping will produce results that are either broken or  awesomely  nonconventional
depending on the user's perspective.

Create an iosrv that allows you to monitor dns requests:

io -c 'tail -f /sys/log/dns' io.dns

The following examples demonstrate some of the internal control interface.

Start  an iosrv with verbose logging and a local control console, and issue several
commands to it:

io -i -v rc.3

fear (set paranoid mode)

h1v (view info on hub 1)

shutup (turn off debugging-level output)

Now connect a shell to the session with no io delay and  issue  'hub'  commands  to
create a new set of usable multiplexed io pipes:

io rc.3 fast (since paranoid mode was set, use 'fast')

hub h3s3 (start new hub 3 with H3in3 as initial input)

hub h3o3 (add an output file H3out3 from Hub 3)

hub h4s4

hub h404 (similarly for Hub 4)

hub h5s5

hub h5e5 (Hub 5 names output H5err5 for mnemonic)

Now open a new window and connect a new rc to the new hubs:

mount -c /srv/rc.3 /n/rc.3 && cd /n/rc.3

rc -i <H3out3/data1 >H4in4/data >[2]H5in5/data &

And finally connect to that persistent rc from a new client:

mount -c /srv/rc.3 /n/rc.3 && cd /n/rc.3

ioshell H3in3/data H4out4/data1 H5err5/data1 ctl/data

(Note  that  identical  results  could  be  obtained  by issuing the commands above
directly to the control console similarly to the first group  of  control  commands




UNIX pipes, pipe(3), srv(3) and aux/consolefs(4)


Not  all  flags  are  sane in combination. The command parser is primitive. Not all
user initiated control actions are error checked. There are no provided options for
giving  clients  different levels of privilege to control the session. Mental inca-
pacity to grapple with the combinatoric possibilities  of  higher-dimensional  pipe
topologies  (see below). Large amount of client connections and disconnections will
produce many processes that may need manual pruning. Some of the semantics are  ad-
hoc  and  users should be provided with more naming and numbering control. Reinven-
tion of the wheel in octagonal form. Parameters such as data bucket size  are  com-
piled-in.  The  whole thing should probably implement itself as a 9p fs rather than
piggybacking on exportfs (4) and pipe (3) files.


"Doug  had  for years and years, and he talked to us continually about it, a notion
of interconnecting computers in grids, and arrays, very  complex,  and  there  were
always problems in his proposals. That what you would type would be linear and what
he wanted was three-dimensional, n-dimensional...I mean he wanted just  topological
connection  of  programs and to build programs with loops and and horrid things. He
had such grandiose ideas and we were saying, the complexity you're generating  just
can't  be fathomed. You don't sit down and you don't type these kind of connections
together. And he persisted with the grandiose ideas where you get into Kirchoff's
law  problems...what  happens if you have a feedback loop and every program doubles
the number of characters, it reads one and writes two? It's got to go somewhere -
synchronization - there's just no way to implement his ideas and we kept trying to
pare him down and weed him down and get something useful and distill it.  What  was
needed,  was  real  ideas...and  there  were  constant discussions all through this
period, and it hit just one night, it just hit, and they went in instantly."

~Ken Thompson on UNIX pipes' origins