.TH IO 1 .SH NAME io, iosrv, ioshell \- persistent multiplexed i/o sessions, or 'screen without a screen' .SH SYNOPSIS .B io [ .B -a -i -p -v ] [ -l .I logfile ] [ .B -c .I cmd ] .I srvname .PP .B io .I srvname [ .B zap .B slow .B fast .B here ] .PP .B iosrv [ .B -hrspv ] [ .B -t sleeptime ] .I srvname .PP .B ioshell .I filefromfd0 filetofd1 filetofd2 ctlfile .PP .SH DESCRIPTION .I Io invokes .IR iosrv (1) to create a system of .IR pipe (3) devices available as a .IR srvfs (4) and starts an .IR rc (1) shell with its file descriptors redirected to these pipes, then uses .IR ioshell (1) as a client for these connections. The overall usage model is somewhat similar to GNU .I screen but without the additional complexities of TTY management. .PP The base behavior of .IR io (1) .I srvname is bimodal, and will function as either a client or server depending on whether .B /srv/srvname exists. If no name is provided, .I io will create or attach to a .B /srv named .B /srv/iorc.$pid containing a persistent .I rc session. Thus, the simplest possible model of use is: .IP .EX io .EE .PP to start a backgrounded .I iosrv hosted persistent rc shell, and then .IP .EX io .EE .PP from any window with access to that .B /srv to connect to it. .PP By default, no connection is made to the initially created .I rc. The .B -a flag will connect the calling window to the .I rc by simply invoking .I io srvname after it has completed the .I iosrv .B /srv setup. Conversely, if the .B -i flag is given, the initial window is run with the .I iosrv server itself foregrounded in interactive control console mode, with logging sent to the initiating window and that window's keyboard input sent to the .B ctl/data file. Otherwise, the output is backgrounded and control messages can only be written via echo to the mounted .B ctl/data pipe. The .B -v option activates verbose debug logging of all the client and server message passing, and .B -l .I logfile redirects logging information in either mode to the specified file, or to .B /tmp/iolog$pid if no filename is given. .PP The .B -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. .PP The .B -c .I command option replaces the default backgrounded .I rc with the command of your choice. .IP .EX io -c cat io.cat .EE .PP will make .IR cat (1) the active process. Subsequent commands of the form .B io io.cat will connect to the running backgrounded .I cat process, allowing for a very simple chat-type application between multiple users. ( .B chmod 666 /srv/cat.io by the controlling user will be necessary first.) For more complex commands a certain amount of ingenuity in string quoting may be required. .PP .I io in its client role accepts no flags. When .B /srv/srvname exists, .I io .I srvname will mount the .B /srv and then start an .I ioshell client attached to a new set of file descriptors requested from the .I iosrv. Multiple clients may connect simultaneously, and clients may disconnect and reconnect freely. The optional arguments [ .B zap fast slow here ] are translated into commands sent to the iosrv ctl file. .I zap clears the log prior to connecting. .I slow and .I 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 transmission.) .I here creates an additional rc on the CLIENT machine attached to the current iosrv and attaches to it. In other words, this allows the client to share a persistent .I rc session back to the HOST .I iosrv and its other clients. An arbitrarily compiled-in maximum of 64 file descriptors can be used progressively for a single hub. .PP The .I ioshell client provides a few features to interface with .I iosrv. It is invoked automatically by .I io and rarely directly by the user. Fundamentally, .I ioshell simply acts to "bucket brigade" data between the user's existing shell file descriptors and the pipes managed by .I iosrv. The .I ioshell is basically transparent to input and output with the exception of providing a set of commands and a communication channel to the .I iosrv. Some text strings are intercepted by the .I ioshell and trigger special actions. In particular: .B remote # , .B local # , .B attach # , .B clear , .B detach , .B hist , and .B hub .I cmdstring are treated as follows. Note that the connection context is relevant in particular for: .IP .EX remote # .EE .PP which creates a new rc session on the HOST machine (the machine running the .I iosrv being targeted) with 3 new Hubs activated and shifts the connection to it. # corresponds 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, .IP .EX local # .EE .PP functions similarly but the rc is hosted by the CLIENT machine (the machine importing the /srv - if both the client and the server are on the same machine, .B remote and .B 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 .B local option makes iosrv the equivalent of a shared .B /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 .I ioshell is attached. .IP .EX attach # .EE .PP shifts to the currently existing .I iosrv .I rc whose lowest Hub # is given. Using new and attach, the user can create additional instances of .I rc connected to the current .I iosrv and switch between them freely. VERY IMPORTANT: as a standard .I rc shell or other traditional textual input/output program uses 3 file descriptors, numbering should proceed by increments of 3 as additonal .I rc are attached to a given .I 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. .IP .EX detach .EE .PP ends the current ioshell attachment to the .I iosrv pipes - it does not affect the remote system in any way, it simply returns control to the original shell. (it also requests a .IR fortune (1) on the way out.) .B clear resets the internal buffers and pointers of the primary set of hubs (H0, H1, and H2). .B hist provides a command history of the user's attached .I ioshell. Note this is not a complete log of all attached input clients, but only of the local client. .B hub .I cmdstring sends cmdstring to the .I iosrv .B ctl file, enabling arbitrary commands to be passed to the session. Notable commands include: .B hub fear to active paranoid mode and .B hub calm to deactivate it. .B hub quit terminates the entire iosrv and kills all reader and writer processes. .B hub debug and .B hub shutup act to start and stop verbose debug output respectively. (Note: the logging information is not sent to the .I ioshell client, but rather to the location specified by the initial .I io server command.). .PP 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 representing a verb, and then usually an additional numeric parameter. The .I io and .I ioshell tools use these commands to perform their actions. .IP .EX hub h1t50 .EE .PP from within an attached .I 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 .B 'h%d%c%d' Hub commands will not be offered in this manpage. .PP The .I iosrv command is usually called from the .I io wrapper script. The options that vary from those of the wrapper script are mostly experimental debugging options. The .B -dhrs flags deactivate the default setup, turn off file descriptor preservation, turn off .IR ramfs (4) and prevent a .B /srv from being posted, respectively. Check the source code for details. .PP In theory, there is nothing preventing the .I 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 .I 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. .PP .SH EXAMPLES For most users and purposes, .B io .I srvname used to both start and connect to a given .B /srv (in combination with any needed network imports) will be the primary mode of usage, along with .B remote # and .B 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 .I iosrv core. .PP Start a session named aug1 and connect to it in the same window as it was launched: .IP .EX io -a aug1 .EE .PP Connect a second client to that session: .IP .EX io aug1 .EE .PP Start another session named rc.2 backgrounded but with non-verbose logging written to the default logfile: .IP .EX (host) io -l rc.2 .EE .PP Connect to that .I rc session from a remote client. First, import the host machine's .B /srv then connect and also clear the backscroll: .IP .EX (client) import -ac HOST /srv .EE .PP .IP .EX (client) io rc.2 zap .EE .PP From within that rc, create another rc attached to the current iosrv beginning on Hub 3 (the first available): .IP .EX (client io:) remote 3 .EE .PP connect another client and switch to that rc: .IP .EX (client) io rc.2 .EE .PP .IP .EX (client io:) attach 3 .EE .PP switch back to the original rc: .IP .EX (client io:) attach 0 .EE .PP share an rc from the client machine back to the iosrv: .IP .EX (client io:) local 6 .EE .PP from inside a connected HOST machine .I ioshell connect to the new rc hosted by the client: .IP .EX (host io:) attach 6 .EE .PP The above series of commands demonstrates the basic principle of referring to multiple rc sessions within a single .I iosrv is that the numbering proceeds by threes, because each .I 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. .PP Create an .I iosrv that allows you to monitor dns requests: .IP .EX io -c 'tail -f /sys/log/dns' io.dns .EE .PP The following examples demonstrate some of the internal control interface. .PP Start an .I iosrv with verbose logging and a local control console, and issue several commands to it: .IP .EX io -i -v rc.3 .EE .PP .IP .EX fear (set paranoid mode) .EE .PP .IP .EX h1v (view info on hub 1) .EE .PP .IP .EX shutup (turn off debugging-level output) .EE .PP 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: .IP .EX io rc.3 fast (since paranoid mode was set, use 'fast') .IP .EX hub h3s3 (start new hub 3 with H3in3 as initial input) .EE .PP .IP .EX hub h3o3 (add an output file H3out3 from Hub 3) .EE .PP .IP .EX hub h4s4 .EE .PP .IP .EX hub h404 (similarly for Hub 4) .PP .IP .EX hub h5s5 .EE .PP .IP .EX hub h5e5 (Hub 5 names output H5err5 for mnemonic) .EE .PP Now open a new window and connect a new .I rc to the new hubs: .IP .EX mount -c /srv/rc.3 /n/rc.3 && cd /n/rc.3 .EE .PP .IP .EX rc -i H4in4/data >[2]H5in5/data & .EE .PP And finally connect to that persistent .I rc from a new client: .IP .EX mount -c /srv/rc.3 /n/rc.3 && cd /n/rc.3 .EE .PP .IP .EX ioshell H3in3/data H4out4/data1 H5err5/data1 ctl/data .EE .PP (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 shown.) .PP .SH SOURCE .B sources/contrib/mycroftiv/iosrv.tgz .SH "SEE ALSO" UNIX pipes, .IR pipe (3) , .IR srv (3) and .IR aux/consolefs (4) .SH BUGS 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 incapacity 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. Reinvention of the wheel in octagonal form. Parameters such as data bucket size are compiled-in. The whole thing should probably implement itself as a 9p fs rather than piggybacking on .I exportfs (4) and .I pipe (3) files. .PP - .PP "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." .PP .I ~Ken Thompson on UNIX pipes' origins .PP .B http://www.princeton.edu/~hos/mike/transcripts/thompson.htm