aboutsummaryrefslogtreecommitdiff
path: root/sys/ki
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /sys/ki
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'sys/ki')
-rw-r--r--sys/ki/README648
-rw-r--r--sys/ki/irafks.x1590
-rw-r--r--sys/ki/kbzard.x60
-rw-r--r--sys/ki/kbzawr.x47
-rw-r--r--sys/ki/kbzawt.x43
-rw-r--r--sys/ki/kbzcls.x37
-rw-r--r--sys/ki/kbzopn.x30
-rw-r--r--sys/ki/kbzstt.x48
-rw-r--r--sys/ki/kclcpr.x50
-rw-r--r--sys/ki/kcldir.x44
-rw-r--r--sys/ki/kcldpr.x44
-rw-r--r--sys/ki/kdvall.x32
-rw-r--r--sys/ki/kdvown.x37
-rw-r--r--sys/ki/kfacss.x35
-rw-r--r--sys/ki/kfaloc.x33
-rw-r--r--sys/ki/kfchdr.x61
-rw-r--r--sys/ki/kfdele.x30
-rw-r--r--sys/ki/kfgcwd.x54
-rw-r--r--sys/ki/kfinfo.x42
-rw-r--r--sys/ki/kfiobf.x110
-rw-r--r--sys/ki/kfiogd.x110
-rw-r--r--sys/ki/kfiolp.x110
-rw-r--r--sys/ki/kfiopl.x110
-rw-r--r--sys/ki/kfiopr.x106
-rw-r--r--sys/ki/kfiosf.x112
-rw-r--r--sys/ki/kfiotx.x157
-rw-r--r--sys/ki/kfioty.x138
-rw-r--r--sys/ki/kfmkcp.x136
-rw-r--r--sys/ki/kfmkdr.x30
-rw-r--r--sys/ki/kfpath.x56
-rw-r--r--sys/ki/kfprot.x33
-rw-r--r--sys/ki/kfrmdr.x30
-rw-r--r--sys/ki/kfrnam.x61
-rw-r--r--sys/ki/kfsubd.x52
-rw-r--r--sys/ki/kfutim.x38
-rw-r--r--sys/ki/kfxdir.x76
-rw-r--r--sys/ki/kgfdir.x124
-rw-r--r--sys/ki/ki.h139
-rw-r--r--sys/ki/kichan.com8
-rw-r--r--sys/ki/kiconnect.x115
-rw-r--r--sys/ki/kiencode.x64
-rw-r--r--sys/ki/kienvreset.x69
-rw-r--r--sys/ki/kierror.x66
-rw-r--r--sys/ki/kiextnode.x50
-rw-r--r--sys/ki/kifchan.x32
-rw-r--r--sys/ki/kifmapfn.x38
-rw-r--r--sys/ki/kifndnode.x40
-rw-r--r--sys/ki/kigchan.x38
-rw-r--r--sys/ki/kighost.x156
-rw-r--r--sys/ki/kignode.x111
-rw-r--r--sys/ki/kii.com15
-rw-r--r--sys/ki/kiinit.x67
-rw-r--r--sys/ki/kilnode.x41
-rw-r--r--sys/ki/kimapchan.x44
-rw-r--r--sys/ki/kimapname.x38
-rw-r--r--sys/ki/kinode.com18
-rw-r--r--sys/ki/kintpr.x36
-rw-r--r--sys/ki/kiopenks.x133
-rw-r--r--sys/ki/kireceive.x71
-rw-r--r--sys/ki/kisend.x33
-rw-r--r--sys/ki/kisendrcv.x20
-rw-r--r--sys/ki/kishownet.x69
-rw-r--r--sys/ki/kixnode.x31
-rw-r--r--sys/ki/kopcpr.x47
-rw-r--r--sys/ki/kopdir.x50
-rw-r--r--sys/ki/kopdpr.x59
-rw-r--r--sys/ki/koscmd.x108
-rw-r--r--sys/ki/ksaread.x21
-rw-r--r--sys/ki/ksawait.x24
-rw-r--r--sys/ki/ksawrite.x21
-rw-r--r--sys/ki/ktzcls.x38
-rw-r--r--sys/ki/ktzfls.x33
-rw-r--r--sys/ki/ktzget.x106
-rw-r--r--sys/ki/ktznot.x74
-rw-r--r--sys/ki/ktzopn.x52
-rw-r--r--sys/ki/ktzput.x125
-rw-r--r--sys/ki/ktzsek.x50
-rw-r--r--sys/ki/ktzstt.x32
-rw-r--r--sys/ki/kzclmt.x45
-rw-r--r--sys/ki/kzopmt.x90
-rw-r--r--sys/ki/kzrdmt.x63
-rw-r--r--sys/ki/kzrwmt.x63
-rw-r--r--sys/ki/kzstmt.x21
-rw-r--r--sys/ki/kzwrmt.x49
-rw-r--r--sys/ki/kzwtmt.x26
-rw-r--r--sys/ki/mkpkg107
-rw-r--r--sys/ki/zzdebug.x120
-rw-r--r--sys/ki/zzrdks.c29
88 files changed, 7549 insertions, 0 deletions
diff --git a/sys/ki/README b/sys/ki/README
new file mode 100644
index 00000000..147ee538
--- /dev/null
+++ b/sys/ki/README
@@ -0,0 +1,648 @@
+ Kernel Interface Package
+ 12-May-85 dct
+ (21-Aug-85)
+
+
+1. Introduction
+
+ The kernel interface package (KI) isolates the IRAF virtual operating
+system (VOS) from the IRAF kernel, permitting access either to the local
+kernel or to an IRAF kernel resident on a remote host, via an IRAF kernel
+server (KS). The KI provides access to files, peripherals and devices,
+and subprocesses irrespective of whether the resource is located on the
+local machine or on a remote node. Since the KI is implemented on top of
+the IRAF kernel the different nodes may run different native operating systems.
+
+
+ +-----------+
+ | | VOS = virtual operating system
+ | V O S | KI = kernel interface
+ | | KS = kernel server
+ +-----------+
+ | :
+ |
+ +-----------+ : +-----------+
+ | | | |
+ | K I |=========:========| K S |==== (etc)
+ | | | |
+ +-----------+ : +-----------+
+ | |
+ | : |
+ +-----------+ +-----------+
+ | | : | |
+ | local | | remote |
+ | kernel | : | kernel |
+ | | | |
+ +-----------+ : +-----------+
+
+ :
+ (host1) (host2)
+
+
+ Architecture of the Kernel Interface
+
+
+2. Conceptual Design
+
+ The purpose of the kernel interface is to permit access to logical files,
+devices, and subprocesses regardless of where such objects physically reside
+in a network. This permits sharing of peripherals such as image displays and
+plotters, data sharing (centralized databases), load sharing (running of
+subprocesses on lightly loaded nodes), and makes such mundane operations as
+copying a file between two nodes possible without developing special purpose
+software and further complicating the user interface.
+
+By addressing these problems by implementation of an interface just above
+the IRAF kernel it becomes possible to remotely access nodes running different
+native operating systems, e.g., UNIX and VMS, with the IRAF kernel on each host
+system resolving the differences between file formats and filenames found
+on the different host systems. Full access to text files and raw peripherals
+is inherent in the scheme regardless of the architecture of the host machine.
+Full access to binary datafiles is possible provided the binary format is
+machine independent, a desirable goal in any case.
+
+The kernel interface is conceived as an optional and invisible interface
+between the IRAF virtual operating system and the IRAF kernel.
+The specifications of the kernel are not affected by the KI, except for the
+addition of a new device driver for talking to remote kernel servers. The VOS
+sees the same kernel interface whether or not the system is configured with a
+KI.
+
+A VOS call to a kernel procedure such as ZOPNBF, for example, is directed
+instead to the KI procedure KOPNBF which in turn calls either the local ZOPNBF
+or passes the call to a remote KS. The VOS still calls the procedure "zopnbf",
+but the external name of this procedure is redefined in <config.h> as "kopnbf",
+permitted substitution of the KI merely by recompilation. When the file is
+opened a channel descriptor is allocated within the KI telling whether the
+channel is local or remote, and if remote giving the KS address on the net,
+and giving the kernel channel number of the file on the node on which it
+resides. The KI channel number instead of the kernel channel number is
+returned to the VOS. Subsequent i/o requests on the channel are also processed
+by the KI, which uses the channel descriptor to determine whether the file
+is local or remote and then fulfils the request.
+
+
+3. Other Network Interfaces
+
+ The kernel interface is not intended to replace or compete with "real"
+network implmentations such as NFS or DECNET. If the local net provides such
+facilities then remote access via the host network is equivalent to a local
+file reference. Few such commercial networks, however, permit equivalent
+access when the different nodes run different operating systems.
+Often the type of access provided by the network is restricted in some way,
+e.g., NFS permits transparent access to remote files but not to remote devices.
+On VMS an IRAF kernel routine which accesses an i/o channel at the QIO level
+is bypassing DECNET hence can only be used to access a local device.
+The kernel server approach neatly sidesteps these problems without preventing
+use of the host networking facilities in cases were it is desirable to do so.
+
+
+4. Performance
+
+ The overhead of the KI for a local file access is one additional procedure
+call per i/o request, e.g., an additional 20-30 microseconds per i/o request.
+A remote file access requires encoding of the request as a KI instruction,
+transmission of the instruction to the remote host, decoding of the instruction
+by the remote host, a kernel access on the remote host, and in the case of a
+read request transmission of the data back to the requesting node where it is
+read out into the caller's buffer. Handshaking is required to return the status
+value after reads and writes to a remote node, hence large transfers will
+significantly reduce the overhead involved in remote file access. Large data
+transfers are automatically transferred in segments by the interface code,
+hence there is no builtin limit on the size of a transfer.
+
+A file open or process spawn requiring connection to a kernel server on a
+remote host is a relatively expensive procedure since it requires spawning of
+the kernel server process on the remote host. Once a process has connected to
+a kernel server on a remote host that server will remain connected for the
+life of the local process, with the single connection providing simultaneous
+access to any number of files, devices, or child processes on the remote host.
+Each local process requires its own kernel server process on the remote node.
+
+
+5. Modifications to the Existing I/O System
+
+ As noted above, implementation of the KI should require minimal
+modifications to existing software. The specific modifications or additions
+required appear to be the following:
+
+
+additions:
+
+ add package KI (kernel interface)
+ add source for the KS (kernel server) process
+ add KS device driver to the kernel (package OS)
+ add ZGHOST (get hostname) primitive to OS
+ add SPP and LIBC include files <knames.h> to map zroutine names
+
+
+modifications:
+
+ add reference to <knames.h> to VOS procedures which access kernel
+ finit.h: install kernel server device driver at process startup
+ modify filename mapping:
+ do not map filenames which begin with a node name
+ prepend CWD to relative filenames if CWD is on a remote node (?)
+
+
+6. Filenames
+
+ Files and processes anywhere in the network may be accessed by prepending
+the node name to the VFN or OSFN of the file. In essence we have extended
+the VFN filename syntax to support node names. The syntax is as follows:
+
+ node "!" filename
+
+The field delimiter "!" is used because it is not used in filenames in AOS,
+UNIX, or VMS. The delimiters ":" and "::", commonly used as node name
+delimiters in commercial networds, were intentionally not used so that network
+filenames may be specified without conflict on systems with host network
+support. Typical filenames using this notation are shown below.
+
+ 2!/dev/iis
+ 1!lib$motd
+ 3!dra0:[user.data]pic.db
+
+An important consideration in choosing the node delimiter character is that
+it not be necessary to quote filenames in common everyday usage. It turns out
+that in the CL "command mode" the character ! is only recognized as a
+metacharacter when it occurs at the beginning of a command (as the OS escape),
+hence quoting of filenames containing ! will not be necessary.
+
+The strategy for resolving such filenames is as follows. The full filename
+including the nodename is passed to the filename mapping code on the local
+machine. If the filename includes a nodename the filename is not mapped.
+The KI receives the filename and strips off the nodename, using it to
+select the node which will execute the kernel primitive. The remainder of
+the filename (minus the nodename) is passed to the KS on the addressed node,
+and the KS performs the filename mapping and passes the mapped filename on
+to the IRAF kernel. Since the filename mapping is carried out by the KS on
+the remote node the filename will be mapped in the context of the remote
+machine, i.e., the mapping will depend upon the native operating system used
+on the remote node. If the KS is itself configured with a kernel interface,
+multiple indirection is possible, permitting gateways onto other networks,
+e.g., "gateway!node!filename".
+
+There should be no penalty for using a self referential node name in a
+filename, i.e., the system should be smart enough to ignore node names
+when the node named is the local node. This permits use of the same absolute
+network filenames in configuration tables on all nodes, without having to
+maintain different sources on the different nodes.
+
+Fully functional filename mapping requires that the IRAF environment variables
+used by a process on the local machine be propagated to the kernel server on
+the remote machine. If this is not done then package directory references,
+etc., appearing in virtual filenames will not be resolved. The kernel server
+will inherit all environment variables except iraf$, since logical directory
+names of the form "node!ldir$file" must be expanded relative to the iraf
+root directory on the remote node. User defined logical directories should
+include an explicit node name to permit access from any node.
+
+
+6.1 External KI Procedures
+
+ The majority of the KI procedures are internal, since the KI interface
+is hidden behind the procedure redefinitions in <knet.h>. Other subsystems
+of the VOS do however occasionally need access to the KI, and the following
+procedures are provided for this purpose.
+
+
+ ki_extnode - Extract (or delimit) the node name field
+ ki_mapchan - Map KI channel into OS channel (or pid) and node name
+
+ len_prefix = ki_extnode (resource, nodename, maxch, nchars)
+ oschan = ki_mapchan (kichan, nodename, maxch)
+
+
+The EXTNODE function is used to extract the node name from a resource name,
+e.g., to produce a simpler name as required by the low level code, or to
+propagate the node name prefix to a second resource name. The MAPCHAN function
+is used to convert a KI channel descriptor into the corresponding OS channel
+number and node name, e.g., for output to the user (the KI channel code is
+meaningless to the user).
+
+
+7. KI Procedures
+
+ Only those procedures in the IRAF kernel which take a filename as an operand
+or which do i/o to a file (or to IPC) need be mapped by the kernel interface.
+This subset of the kernel includes all the file primitives, all the device
+drivers, and some exception handling procedures.
+
+ zfacss - determine file accessibility
+ zfaloc - allocate a file
+ zfchdr - change default directory (??)
+ zfdele - delete a file
+ zfgcwd - get default directory (??)
+ zfinfo - get directory info on a file
+ zfmkcp - make a null length copy of a file
+ zfprot - set, remove, or query file protection
+ zfrnam - rename a file
+ zopdir - open a directory
+ zgfdir - get next filename from a directory
+
+ zopdpr - open a detached process
+ zcldpr - close a detached process
+ zopcpr - open a connected subprocess
+ zclcpr - close a connected subprocess
+ zintpr - interrupt a subprocess
+
+ zfiobf - binary file driver
+ zfiolp - line printer driver
+ zfiomt - magtape driver
+ zfiopl - plotter driver
+ zfiopr - ipc driver
+ zfiosf - static file driver
+ zfiotx - text file driver
+ zfioty - terminal driver
+
+
+The basic function of a KI procedure is to determine which host is to execute
+the kernel primitive, call the local or remote kernel to execute the primitive,
+and return the results to the calling program.
+
+
+7.1 Pseudocode for a KI Procedure
+
+ Consider the common case of reading a file on a remote host. The file
+open procedure must connect to the KS on the remote host, command the remote
+kernel to open the file, and read back the status of the open. Whether the
+file is on the local or remote node, a channel descriptor must be set up
+to tell the KI i/o primitives how to access the file.
+
+
+# KOPNBF -- KI version of ZOPNBF (open binary file).
+
+procedure kopnbf (osfn, mode, status)
+
+begin
+ ks = get_kernel_server (osfn)
+ if (ks is the local node)
+ call zopnbf (osfn, mode, status)
+ else {
+ encode KI instruction for zopnbf
+ write instruction to KS
+ read reply from KS
+ if (error on channel to KS)
+ return (status=ERR)
+ }
+
+ set up channel descriptor (set channel codes of KS and file)
+end
+
+
+# GET_KERNEL_SERVER -- Return a channel to the kernel server controlling
+# a virtual filename.
+
+int procedure get_kernel_server (vfn)
+
+begin
+ extract node name from vfn
+ if (no node name given)
+ return (0)
+ else if (node is already connected)
+ return (node channel)
+ else {
+ connect to the KS on the remote node
+ save channel of node in channel table
+ return (node channel)
+ }
+end
+
+
+# KARDBF -- KI version of ZARDBF (read from a binary file). The read will not
+# be asynchronous if the file is resident on a remote node. The size of a
+# transfer is not limited by the maximum block of the channel.
+
+procedure kardbf (chan, buf, maxchars, offset)
+
+begin
+ if (ks[chan] == 0)
+ call zardbf (chan, buf, maxchars, offset)
+ else {
+ encode KI instruction for ZARDBF
+ write KI instruction to remote kernel server
+ read back the KI header of the response
+
+ if (read status ok and KI status for read ok) {
+ transfer data from channel directly into callers buffer,
+ in blocks no larger than the channel block size
+ save channel status for KAWTBF
+ }
+ }
+end
+
+
+7.2 Data Structures
+
+ The data structures required by the kernel interface are small and are
+statically allocated.
+
+
+7.2.1 Host Name Table
+
+ The host name table (HNT) lists all of the hosts in the network which the
+KI can access, giving for each node the node filename of the kernel server
+process on that node, and a list of aliases (node names) for the node.
+The host name table is the text file "dev$hosts". The format of the file
+is illustrated by the following example:
+
+
+ 1!/iraf/lib/irafks.e : 1 a vax1 aquila
+ 2!/iraf/lib/irafks.e : 2 b vax2 lyra
+ 3!usr1\:[irafx.lib]irafks.exe : 3 vax3 vela
+ 5!/iraf/lib/irafks.e : 5 c vax5 carina
+ 6!usr1\:[irafx.lib]irafks.exe : 6 vax6 draco
+ 11!/iraf/lib/irafks.e : 11 sun1 petunia
+
+
+The format of an entry in this table is "server ':' aliases", where "server"
+is a machine dependent, colon delimited string to be passed to the ZFIOKS
+driver, and where the aliases are a sequence of null delimited logical names
+by which the high level code or the user can refer to the nodes. The first
+field, e.g., "server", is limited to 80 characters, the aliases to 8 characters
+(longer names will be silently truncated, either limit may be increased if
+necessary). Up to 8 aliases may be specified. The alias "0" will be
+automatically added to the alias list of the local node by the KI; this alias
+is used by the high level code to force a file to be accessed on the local node.
+The local node should also include as an alias the name returned by ZGHOST.
+The maximum number of nodes is a <config.h> parameter. The entries may appear
+in any order.
+
+
+7.2.2 Node Descriptor Table
+
+ For each entry in the host name table there is a corresponding entry in
+the node descriptor table (NDT). The fields of the NDT are initialized
+when the first filename containing a node reference is processed. When a
+kernel server is opened on a node the N_KSCHAN field is set to the channel
+code returned by the kernel server device driver.
+
+
+ int n_nnodes # number of nodes in table
+
+ struct node_descriptor {
+ int n_kschan # KS i/o channel or NULL
+ int n_local # set to YES for the local node
+ int n_nalias # number of aliases for this node
+ char n_server[64] # netname!process
+ char n_alias[8,8] # aliases
+ } ndt[MAX_NODES]
+
+
+Runtime node references are satisfied by searching the NDT for the specified
+alias. If the referenced node is the local node a NULL channel number is
+returned. If the N_KSCHAN field of the referenced node is null a kernel
+server is spawned and the channel number of the server returned. If a kernel
+server is already connected mapping an alias into a channel number is very
+fast (compared to a file open). Once a server is spawned it remains connected
+until the local process shuts down.
+
+
+7.2.3 Channel Descriptor Table
+
+ Each open file or connected subprocess requires one channel descriptor
+for each i/o channel or process id. The K_KSCHAN field will contain NULL if
+the channel resides on the local node. Channel descriptors are allocated at
+file or device open time or process connect time and are freed at close or
+disconnect time. If the channel is connected to a kernel server, the K_OSCHAN
+and K_PID fields will contain the OS channel number or process id of the
+resource as returned by the kernel server on the remote node.
+
+
+ struct channel_descriptor {
+ int k_kschan # KS channel (NULL if local node)
+ int k_oschan # OS channel number or PID
+ int k_status # status for the ZAWAIT call
+ } cdt[MAX_CHANNELS]
+
+
+7.3 KII Instruction Format
+
+ The kernel interface instruction format (KII) is the binary encoding of
+the data blocks sent to and received from the remote kernel server to execute
+a call to a kernel procedure. This format is machine independent, i.e.,
+it is defined in a way that is independent of the byte ordering, char size,
+etc. used by a node. The KII format provides a machine independent interface
+for the execution of all kernel subroutines as well as for text file i/o.
+Binary data blocks passed via the binary file i/o procedures are not affected,
+hence if a machine independent binary format is desired it must be implemented
+at a level higher than the KI.
+
+The KII format selected is a fixed format to simplify encode/decode and
+packet transfer (if the transfer medium is stream oriented fixed size packets
+are simpler to extract from the stream). For media such as Ethernet
+performance depends more upon the number of packets transferred than upon
+the size of a packet, so there is little penalty for wasted space in a fixed
+size packet. The maximum amount of information necessary to encode a kernel
+procedure call is limited (the argument lists are never large) hence it is
+easy to set an upper bound on the packet size. The KII packet structure is
+shown below.
+
+ struct kii_packet {
+ int p_opcode # instruction opcode
+ int p_subcode # subcode (for device drivers)
+ int p_arg[13] # procedure arguments
+ int p_sbuflen # nchars in string buffer
+ char p_sbuf[255] # string buffer
+ }
+
+ sizeof (struct kii_packet) == ((16*4)+256) == 320 bytes
+
+
+The OPCODE and SUBCODE fields identify the kernel procedure to be executed.
+Each procedure argument is passed in the corresponding field of the ARG array;
+for string arguments this field contains the offset of the string value in
+the P_SBUF field. Procedure argument N is passed in field N of the ARG array.
+P_SBUFLEN is the number of chars in the string buffer, including the EOS at
+the end of each string.
+
+Before transmission of the packet over the net the packet is encoded in
+a machine independent form. The 16 integer fields are converted into MII
+32 bit signed integer format, and the 256 character string buffer is packed
+one byte per character (only the first SBUFLEN characters are packed). The
+inverse transformation is performed by the kernel server on the remote node
+before accessing the contents of the packet.
+
+Most kernel procedures return a status value and/or data. The KII packet
+structure is used both to remotely execute a kernel procedure and to return
+the status value and any scalar or string output arguments. In the case of
+text file i/o the text data is passed in the SBUF field. Procedures which
+return a data structure (e.g., ZFINFO) may pass the data structure as a
+sequence of ARG array elements, encode the structure in chararacter form
+in SBUF, or pass the structure in a separate packet. In most cases a single
+packet will be used for greater efficiency and to avoid the need to
+explicitly encode the return value.
+
+The purpose of the SUBCODE field is to exploit the fact that the text and
+binary file drivers each have the same set of driver procedures, each with
+the same set of arguments. The OPCODE field identifies the device driver
+and the SUBCODE field the driver function, e.g., OPN, ARD, AWR, AWT, etc.
+
+
+8. KS Driver
+
+ Connecting and disconnecting kernel servers, and all i/o to connected
+kernel servers, is provided by the KS driver. To the KI in the calling
+process a KS behaves like a synchronous binary file opened for readwrite
+access. The driver is patterned after a binary file driver, allowing the
+server process to be connected to FIO as a streaming binary file. Normally,
+however, the driver procedures will be called directly by the KI.
+
+
+ zopnks (server, mode, chan)
+ zawrks (chan, buf, nbytes, offset)
+ zardks (chan, buf, maxbytes, offset)
+ zawtks (chan, status)
+ zsttks (chan, what, lvalue)
+ zclsks (chan, status)
+
+
+The entry points of the KS driver are shown above. The argument SERVER is
+the network pathname of the kernel server process, e.g., "2!/iraf/lib/ks.e".
+There no requirement, however, that the named process be a kernel server
+process. The driver will attempt to execute and set up readwrite streaming
+i/o to any process, hence the KS driver may be useful for network functions
+other than the kernel interface.
+
+
+9. Kernel Server Process
+
+ The kernel server process is an IRAF process with a standard IRAF Main
+but a special ONENTRY procedure and no task dictionary (like the CL).
+The server communicates with a KI via the binary streams CLIN and CLOUT,
+both of which are connected to a single channel in the calling process.
+The server process contains an interpreter capable of calling any kernel
+procedure which does i/o. In addition, the kernel server contains enough
+of FIO to map filenames and read and write CLIN and CLOUT.
+
+
+10. Filename Mapping Details
+
+ The system interface procedures used for filename mapping must be trapped
+by the KI to deal with node pathnames. The relevant procedures are the
+following:
+
+ zfnbrk break vfn into its component parts
+ zfchdr change directory
+ zfgcwd get default directory
+ zfxdir extract directory prefix
+ zfpath convert vfn to pathname
+ zfsubd fold subdirectory into pathname
+
+The first routine, ZFNBRK, merely parses filenames into their component fields
+and it should be possible for the same routine to be used on all nodes without
+help from the KI. The remaining routines are fundamental to the action of
+the KI.
+
+
+10.1 Default Directory
+
+ Normally, either the kernel or the host system keeps track of the default
+directory. This remains the case when the KI is in use, provided the default
+directory is on the local node. If the default directory is changed to some
+different node the following actions are taken by the KI:
+
+ [1] Extract node prefix and save in a KI common for use during filename
+ mapping.
+
+ [2] Execute ZFCHDR on the remote node (minus the node prefix) to set
+ the node-relative default directory.
+
+All subsequent runtime file references are mapped as follows:
+
+ [1] The default node prefix is prepended to all filenames which do
+ not include an explicit node name prefix.
+
+ [2] Normal filename mapping is performed, i.e., filename mapping is
+ disabled on the local node (since the filename has a node prefix),
+ deferring mapping to the kernel server on the remote node.
+
+All normal runtime filename mapping starts with a call to ZFXDIR. If ZFXDIR
+returns anything the filename is assumed to be host dependent and is not mapped.
+Hence we want ZFXDIR to return the entire VFN as if it were an OSDIR name,
+if the VFN includes a node prefix and the node referenced is not the local
+node. ZFPATH and ZFSUBD must behave similarly.
+
+
+10.2 Semicode
+
+
+procedure kfchdr (osdir, status)
+
+begin
+ server = ki_connect (osdir)
+
+ if (server == NULL) {
+ # Directory is on the local node.
+
+ default node = local node
+ call zfchdr (osdir_minus_node_prefix, status)
+
+ } else {
+ # Directory is on a remote node.
+
+ pass zfchdr request to remote node
+ if (request is successful)
+ default node = remote node
+ }
+end
+
+
+procedure kfgcwd (osdir, nchars)
+
+begin
+ if (default node is the local node)
+ call zfgcwd to get default directory
+ else
+ pass zfgcwd request to remote node
+
+ return (default_node // default_directory)
+end
+
+
+procedure zfxdir (vfn, osdir, maxch, nchars)
+
+begin
+ extract node name
+
+ if (no node name specified)
+ node name = default node
+
+ if (node is the local node)
+ pass the request to the local kernel
+ else
+ return (node // vfn)
+end
+
+
+procedure zfpath (vfn, pathname, maxch, nchars)
+
+begin
+ extract node name
+
+ if (no node name specified)
+ node name = default node
+
+ if (node is the local node) {
+ call zfpath to compute local pathname
+ return (node // pathname)
+ } else
+ return (node // vfn)
+end
+
+
+procedure zfsubd (osfn, maxch, subdir, nchars)
+
+begin
+ extract node name
+
+ if (no node name specified)
+ node name = default node
+
+ if (node is the local node) {
+ call zfsubd to compute local pathname
+ return (node // pathname)
+ } else
+ return (node // vfn // "subdir/")
+end
diff --git a/sys/ki/irafks.x b/sys/ki/irafks.x
new file mode 100644
index 00000000..7d4598b0
--- /dev/null
+++ b/sys/ki/irafks.x
@@ -0,0 +1,1590 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <finfo.h>
+include <fset.h>
+include <fio.h>
+include <clset.h>
+include <knet.h>
+include "ki.h"
+
+# KSERVER.X -- The IRAF kernel server, used to serve up kernel functions on
+# a remote host.
+
+define DEBUG_FILE "/tmp/ks.out" # MACHDEP
+#define DEBUG_FILE "iraftmp:ks.out"
+define DEBUG NO
+#define DEBUG YES
+
+define DEF_LENIOBUF 32768 # reallocated if too small
+define SZ_TXBUF 1024 # handy text buffer
+define LEN_BFDRIVER 8 # actually 6, but 8 is a power of 2
+define LEN_TXDRIVER 8 # no. entry points in tx driver
+define MAX_BFDRIVERS 10 # max binary file devices
+define MAX_TXDRIVERS 2 # max text file devices
+
+define LEN_BFDD (LEN_BFDRIVER*MAX_BFDRIVERS)
+define LEN_TXDD (LEN_TXDRIVER*MAX_TXDRIVERS)
+
+define ZOPNTX txdd[($1)] # text files
+define ZCLSTX txdd[($1)+1]
+define ZGETTX txdd[($1)+2]
+define ZPUTTX txdd[($1)+3]
+define ZFLSTX txdd[($1)+4]
+define ZSEKTX txdd[($1)+5]
+define ZNOTTX txdd[($1)+6]
+define ZSTTTX txdd[($1)+7]
+
+define ZOPNBF bfdd[($1)] # binary files
+define ZCLSBF bfdd[($1)+1]
+define ZARDBF bfdd[($1)+2]
+define ZAWRBF bfdd[($1)+3]
+define ZAWTBF bfdd[($1)+4]
+define ZSTTBF bfdd[($1)+5]
+
+
+# IRAFKS -- The main entry point of the iraf kernel server task. The kernel
+# server program is not CL callable but is instead spawned by the OS to listen
+# listen on a socket. The ONENTRY procedure gains control from the IRAF main
+# at process startup, before the in task interpreter is entered. The t_irafks
+# procedure is never actually called by the interpreter as the TASK statement
+# suggests. The purpose of the task statement is to give us an IRAF main.
+
+task irafks = t_irafks
+procedure t_irafks()
+begin
+end
+
+
+# ONENTRY -- The real task executed by the irafks.e executable.
+
+int procedure onentry (prtype, bkgfile, cmd)
+
+int prtype #I process type flag (not used)
+char bkgfile[ARB] #I bkgfilename if detached process (not used)
+char cmd[ARB] #I optional command (used to flag irafks type)
+
+bool error_restart
+int debuginit, chan, junk
+char osfn[SZ_PATHNAME], debugfile[SZ_PATHNAME]
+
+int getpid(), open()
+data error_restart /false/
+data debuginit /DEBUG/
+
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ # Debug messages can be enabled either by compiling with DEBUG=YES
+ # or by running the kernel server with "-d debugfile" on the command
+ # line (a bit of a trick using the detached process syntax).
+
+ if (prtype == PR_DETACHED) {
+ debug = YES
+ call strcpy (bkgfile, debugfile, SZ_PATHNAME)
+ } else {
+ debug = debuginit
+ call strcpy (DEBUG_FILE, debugfile, SZ_PATHNAME)
+ }
+
+ # If an error occurs and we go through error restart, deadlock will
+ # probably occur as the client may be awaiting a status packet while
+ # upon restart we will be awaiting a command packet. Hence if restart
+ # occurs, shut the kernel server down.
+
+ if (error_restart) {
+ call zclsks (chan, junk)
+ return (PR_EXIT)
+ } else
+ error_restart = true
+
+ # Open the network connection to the host process.
+ call strpak (cmd, osfn, SZ_PATHNAME)
+ call zopnks (osfn, READ_WRITE, chan)
+
+ # Open the debug file if so indicated. The value of the debug flag
+ # should be patched before execution with a debugger if debug output
+ # is desired.
+
+ if (debug == YES) {
+ spy = open (debugfile, APPEND, TEXT_FILE)
+ call fseti (spy, F_FLUSHNL, YES)
+
+ call fprintf (spy, "[%d] -------------------------\n")
+ call pargi (getpid())
+ call fprintf (spy, "server channel = %d\n")
+ call pargi (chan)
+ }
+
+ # Redirect the standard input and output of the kernel server task
+ # to the null file to prevent deadlock if the task unexpectedly
+ # reads or writes the standard input or output.
+
+ call fredir (STDIN, "dev$null", READ_ONLY, TEXT_FILE)
+ call fredir (STDOUT, "dev$null", WRITE_ONLY, TEXT_FILE)
+ call fredir (STDERR, "dev$null", WRITE_ONLY, TEXT_FILE)
+
+ # Serve up the kernel until EOF is seen on the input stream.
+ if (chan != ERR)
+ call kserver (chan, chan, DEF_LENIOBUF)
+
+ # Exit w/o running interpreter.
+ call zclsks (chan, junk)
+ return (PR_EXIT)
+end
+
+
+# KSERVER -- Kernel server interpreter. This procedure is called from the
+# kernel server program to interpret and execute (serve up) kernel instructions
+# issued by a remote host. Execution terminates when EOF is seen on the input
+# channel. All i/o is all low level since the level of function implemented
+# here is that of the iraf kernel. This code executes in a private subprocess
+# hence we need not worry about memory usage or reentrancy.
+#
+# NOTE -- Avoid passing packet data to subprocedures, since the kernel
+# procedures called directly or indirectly by this code may themselves use
+# the local KII packet data structure.
+
+procedure kserver (in, out, buflen)
+
+int in # input channel, a binary stream
+int out # output channel, a binary stream
+int buflen # iobuf size or 0
+
+pointer iobuf, op, top
+long fi[LEN_FINFO]
+char curdir[SZ_PATHNAME]
+int len_iobuf, status, i, nchars, opcode, subcode, arg1, arg2, arg3
+int bfdd[LEN_BFDD], txdd[LEN_TXDD]
+
+char txbuf[SZ_TXBUF], queue[SZ_FNAME]
+char osfn1[SZ_PATHNAME], osfn2[SZ_PATHNAME], temp[SZ_PATHNAME]
+char o_str[SZ_LINE], s_str[SZ_LINE]
+int ks_receive(), ks_send(), strlen(), envscan()
+int diropen(), gstrcpy(), getline()
+include "kii.com"
+errchk ks_error
+define reply_ 91
+
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ if (debug == YES) {
+ call fprintf (spy, "start kernel server, in=%d, out=%d\n")
+ call pargi (in)
+ call pargi (out)
+ }
+
+ # Allocate a buffer for read and write requests on a channel. We always
+ # transfer data immediately, before accepting another request, hence
+ # the same buffer may be reused for all requests.
+
+ if (buflen > 0)
+ len_iobuf = buflen / SZB_CHAR
+ else
+ len_iobuf = DEF_LENIOBUF / SZB_CHAR
+ call malloc (iobuf, len_iobuf, TY_CHAR)
+
+ if (debug == YES) {
+ call fprintf (spy, "kernel server, len_iobuf=%d\n")
+ call pargi (len_iobuf)
+ }
+
+ # Load the device drivers.
+ call ks_loadbf (bfdd)
+ call ks_loadtx (txdd)
+
+ # Initialize our record of the current working directory.
+ curdir[1] = EOS
+
+ # Enter the main interpreter loop of the kernel server, reading and
+ # processing kernel requests from the host until EOF is seen. The
+ # host is completely in control. Kernel requests are passed to the
+ # local kernel (or to yet another kernel server) unchanged except
+ # for filenames, which must be mapped in the context of the local
+ # machine.
+
+ while (ks_receive (in) > 0) {
+ opcode = p_opcode
+ subcode = p_subcode
+ arg1 = p_arg[1]
+ arg2 = p_arg[2]
+ arg3 = p_arg[3]
+
+ p_sbuflen = 0
+
+ if (debug == YES) {
+ call ks_op2str (opcode, subcode, o_str, s_str)
+ if (opcode < KI_ZFIOBF) {
+ call fprintf (spy, "opcode=%s, arg[] =")
+ call pargstr (o_str)
+ } else {
+ call fprintf (spy, "opcode=%s), subcode=%s, arg[] =")
+ call pargstr (o_str)
+ call pargstr (s_str)
+ }
+ do i = 1, 10 {
+ call fprintf (spy, " %d")
+ call pargi (p_arg[i])
+ }
+ call fprintf (spy, "\n")
+ }
+
+ switch (opcode) {
+ case KI_ENVINIT:
+ # Called shortly after process startup to pass the environment
+ # list to the kernel server (req'd for filename mapping).
+ # May also be called after process startup to add entries to
+ # the environment list. Note that the kernel server process,
+ # since it is an IRAF process, will have read the zzsetenv.def
+ # file to define the standard variables during process startup,
+ # but the client must transmit its environment list anyhow to
+ # set the values of any newly defined variables.
+
+ # Get the packed environment list string. If this is small
+ # it is sent in the packet string buffer, otherwise the data
+ # follows in a separate record.
+
+ nchars = arg1
+ if (nchars <= SZ_SBUF)
+ status = envscan (p_sbuf)
+ else {
+ if (len_iobuf < nchars) {
+ call realloc (iobuf, nchars, TY_CHAR)
+ len_iobuf = nchars
+ }
+
+ call zardks (in, Memc[iobuf], nchars, long(0))
+ call zawtks (in, status)
+ if (status != nchars)
+ break
+
+ # Unpack it and process it into the symbol table.
+ call strupk (Memc[iobuf], Memc[iobuf], nchars)
+ status = envscan (Memc[iobuf])
+ }
+
+ if (debug == YES) {
+ call fprintf (spy, "%d environment entries scanned\n")
+ call pargi (status)
+ }
+
+ # Do not send a status packet back for single variable updates.
+ if (nchars < SZ_SBUF)
+ next
+ else if (status < 0)
+ break
+
+ # The environment variables HOST, IRAF, and TMP may differ
+ # from node to node. The ZGTENV primitive in the local
+ # kernel will pick up the local values of these variables
+ # from the HSI global include file <iraf.h>. This happens
+ # automatically if the variables are not defined in the
+ # environment list. The simplest way to keep them out of
+ # the environment list is to exclude them from the list when
+ # it is composed by ki_openks() on the client node, so we
+ # do not have to do anything here.
+
+ case KI_SETROOT:
+ # Called to set the pathname of the root iraf directory on
+ # the local node. This need not be the same as on the client
+ # node hence we must override the definition of "iraf" in the
+ # environment list. We are passed the OS pathname of the
+ # server process (i.e., this process) which is assumed to be
+ # resident in iraf$lib on the current node. The pathname of
+ # iraf$ is therefore obtained by a call to ZFXDIR followed by
+ # a call to ZFSUBD with subdirectory "..".
+
+ # NOTE -- This function is obsoleted by the above code which
+ # sets the values of HOST, IRAF, and TMP from <iraf.h>. Leave
+ # it in for a while nonetheless, just in case it is called.
+
+ call strcpy (p_sbuf[arg1], osfn1, SZ_PATHNAME)
+ call zfxdir (osfn1, osfn2, SZ_PATHNAME, nchars)
+ call zfsubd (osfn2, SZ_PATHNAME, "..", nchars)
+ call strcpy ("set iraf=", osfn1, SZ_PATHNAME)
+ call strcat (osfn2, osfn1, SZ_PATHNAME)
+
+ status = envscan (osfn1)
+
+ if (debug == YES) {
+ call fprintf (spy, "%s\n")
+ call pargstr (osfn1)
+ }
+
+ if (status < 1)
+ break
+
+ case KI_FMAPFN:
+ # Map a filename in the context of the server node.
+ call strcpy (p_sbuf[arg1], osfn1, SZ_PATHNAME)
+ iferr (call ks_fmapfn (osfn1, temp, SZ_PATHNAME))
+ status = ERR
+ else {
+ call strupk (temp, p_sbuf, SZ_SBUF)
+ p_sbuflen = strlen (p_sbuf)
+ status = p_sbuflen
+ }
+
+ case KI_ZFACSS:
+ # Test file accessibility and/or type.
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn1, SZ_PATHNAME))
+ status = ERR
+ else
+ call zfacss (osfn1, arg2, arg3, status)
+
+ case KI_ZFALOC:
+ # Preallocate space for a file.
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn1, SZ_PATHNAME))
+ status = ERR
+ else
+ call zfaloc (osfn1, arg2, status)
+
+ case KI_ZFCHDR:
+ # Change the default directory.
+
+ if (debug == YES) {
+ call fprintf (spy, "change directory to `%s'\n")
+ call pargstr (p_sbuf[arg1])
+ }
+
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn1, SZ_PATHNAME))
+ status = ERR
+ else
+ call zfchdr (osfn1, status)
+
+ # Save the logical name of the new default directory, but only
+ # if the zfchdr request is successful.
+
+ if (status != ERR)
+ call strcpy (temp, curdir, SZ_PATHNAME)
+
+ case KI_ZFDELE:
+ # Delete a file.
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn1, SZ_PATHNAME))
+ status = ERR
+ else
+ call zfdele (osfn1, status)
+
+ case KI_ZFGCWD:
+ # Get the name of the current default directory. Return the
+ # unmapped name rather than the mapped OSFN because the client
+ # deals with unmapped pathnames when the file resides on a
+ # remote node.
+
+ if (curdir[1] == EOS) {
+ call zfgcwd (osfn1, SZ_PATHNAME, status)
+ call strupk (osfn1, p_sbuf, SZ_SBUF)
+ } else
+ status = gstrcpy (curdir, p_sbuf, SZ_SBUF)
+
+ p_arg[2] = 1
+ p_sbuflen = strlen (p_sbuf)
+
+ case KI_ZFINFO:
+ # Get directory info for a file.
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn1, SZ_PATHNAME))
+ status = ERR
+ else
+ call zfinfo (osfn1, fi, status)
+
+ if (status != ERR) {
+ # Return the integer part of the FI structure in args 2+.
+ do i = 1, LEN_FINFO
+ p_arg[i+1] = fi[i]
+
+ # Return the owner string in the string buffer.
+ call strupk (FI_OWNER(fi), p_sbuf, SZ_SBUF)
+ p_sbuflen = strlen (p_sbuf)
+ }
+
+ case KI_ZFMKCP:
+ # Make a null length copy of a file.
+ iferr {
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn1, SZ_PATHNAME)
+ call strcpy (p_sbuf[arg2], temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn2, SZ_PATHNAME)
+ } then {
+ status = ERR
+ } else
+ call zfmkcp (osfn1, osfn2, status)
+
+ case KI_ZFMKDR:
+ # Make a new directory.
+ iferr {
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn1, SZ_PATHNAME)
+ } then {
+ status = ERR
+ } else
+ call zfmkdr (osfn1, status)
+
+ case KI_ZFPROT:
+ # Set or query file protection.
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn1, SZ_PATHNAME))
+ status = ERR
+ else
+ call zfprot (osfn1, arg2, status)
+
+ case KI_ZFRNAM:
+ # Rename a file.
+ iferr {
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn1, SZ_PATHNAME)
+ call strcpy (p_sbuf[arg2], temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn2, SZ_PATHNAME)
+ } then {
+ status = ERR
+ } else
+ call zfrnam (osfn1, osfn2, status)
+
+ case KI_ZFRMDR:
+ # Remove a directory.
+ iferr {
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn1, SZ_PATHNAME)
+ } then {
+ status = ERR
+ } else
+ call zfrmdr (osfn1, status)
+
+ case KI_ZDVALL:
+ # Allocate or deallocate a device.
+ if (debug == YES) {
+ call fprintf (spy, "allocate `%s' flag=%d\n")
+ call pargstr (p_sbuf[arg1])
+ call pargi (arg2)
+ }
+ call strpak (p_sbuf[arg1], temp, SZ_PATHNAME)
+ call zdvall (temp, arg2, status)
+
+ case KI_ZDVOWN:
+ # Query device allocation.
+ call strpak (p_sbuf[arg1], osfn1, SZ_PATHNAME)
+ call zdvown (osfn1, temp, SZ_PATHNAME, status)
+ call strupk (temp, p_sbuf, SZ_SBUF)
+ p_sbuflen = strlen (p_sbuf)
+
+ case KI_ZFUTIM:
+ # Update thje file modify time.
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ if (debug == YES) {
+ call fprintf (spy, "utime `%s' atime=%d mtime=%d\n")
+ call pargstr (temp)
+ call pargi (arg2)
+ call pargi (arg3)
+ }
+ iferr (call ks_fmapfn (temp, osfn1, SZ_PATHNAME))
+ status = ERR
+ else
+ call zfutim (osfn1, arg2, arg3, status)
+
+ case KI_ZOPDIR:
+ # Open a directory for reading. Since we must perform the
+ # inverse mapping we use the high level DIROPEN package
+ # rather than call the kernel directly.
+
+ if (debug == YES) {
+ call fprintf (spy, "open directory `%s', mode %d\n")
+ call pargstr (p_sbuf[arg1])
+ call pargi (arg2)
+ }
+
+ call strcpy (p_sbuf[arg1], osfn1, SZ_PATHNAME)
+ iferr (status = diropen (osfn1, arg2))
+ status = ERR
+
+ if (debug == YES) {
+ call fprintf (spy, "diropen returns %d\n")
+ call pargi (status)
+ }
+
+ case KI_ZCLDIR:
+ # Close a directory file.
+
+ iferr (call close (arg1))
+ status = ERR
+ else
+ status = OK
+
+ case KI_ZGFDIR:
+ # Get the next filename from a directory. To reduce traffic
+ # on the net we return many filenames at once. The reverse
+ # mapping must be performed locally, returning VFN's to the
+ # client process.
+
+ top = iobuf + min (len_iobuf, arg2)
+ op = iobuf
+
+ # Fill the output buffer. Set argument 2 to 1 if EOF is seen
+ # on the directory.
+
+ arg2 = 1
+ iferr {
+ while (getline (arg1, Memc[op]) != EOF) {
+ op = op + strlen (Memc[op])
+ if (op + SZ_FNAME >= top) {
+ arg2 = 0
+ break
+ }
+ }
+ } then {
+ status = ERR
+ p_arg[2] = arg2
+ goto reply_
+ }
+
+ # If the data is small enough return it in the string buffer,
+ # else return it as a second record.
+
+ nchars = op - iobuf
+ if (nchars <= SZ_SBUF) {
+ call amovc (Memc[iobuf], p_sbuf, nchars)
+ p_sbuflen = nchars
+ status = nchars
+ # goto reply_
+
+ } else {
+ p_arg[1] = nchars
+ if (ks_send (out, opcode, subcode) == ERR)
+ return
+
+ call chrpak (Memc[iobuf], 1, Memc[iobuf], 1, nchars)
+ call zawrks (out, Memc[iobuf], nchars, long(0))
+ call zawtks (out, status)
+ if (status <= 0)
+ return
+
+ next
+ }
+
+ case KI_ZOSCMD:
+ # Issue a command to the local host command interpreter.
+ # Spool the output in a file and return the name of the
+ # file to the client so that it can recover the output via
+ # the text file i/o interface.
+
+ call strpak (p_sbuf[arg1], txbuf, SZ_TXBUF)
+ call strpak ("", osfn1, SZ_PATHNAME)
+ call mktemp ("tmp$zos", temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn2, SZ_PATHNAME)
+
+ call zoscmd (txbuf, osfn1, osfn2, osfn2, status)
+
+ call strupk (osfn2, p_sbuf, SZ_SBUF)
+ p_sbuflen = strlen (p_sbuf)
+
+ case KI_ZOPDPR:
+ # Open a detached process (submit bkg job).
+ iferr {
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn1, SZ_PATHNAME)
+ call strcpy (p_sbuf[arg2], temp, SZ_PATHNAME)
+ call ks_fmapfn (temp, osfn2, SZ_PATHNAME)
+ call strcpy (p_sbuf[arg3], queue, SZ_FNAME)
+ } then {
+ status = ERR
+ } else
+ call zopdpr (osfn1, osfn2, queue, status)
+
+ case KI_ZCLDPR:
+ # Close a detached process.
+ call zcldpr (arg1, arg2, status)
+
+ case KI_ZOPCPR:
+ # Open a connected subprocess.
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn1, SZ_PATHNAME))
+ status = ERR
+ else {
+ call zopcpr (osfn1, arg2, arg3, status)
+ p_arg[2] = arg2
+ p_arg[3] = arg3
+ }
+
+ case KI_ZCLCPR:
+ # Close a connected subprocess.
+ call zclcpr (arg1, status)
+
+ case KI_ZINTPR:
+ # Interrupt a connected subprocess.
+ call zintpr (arg1, arg2, status)
+
+ case KI_ZFIOBF,KI_ZFIOLP,KI_ZFIOPL,KI_ZFIOPR,KI_ZFIOSF,KI_ZFIOGD:
+ # Binary file drivers.
+ iferr (call ks_zfiobf (in, out, iobuf, len_iobuf, bfdd))
+ break
+ else
+ next
+
+ case KI_ZFIOTX, KI_ZFIOTY:
+ # Text file drivers.
+ iferr (call ks_zfiotx (in, out, iobuf, len_iobuf, txdd))
+ break
+ else
+ next
+
+ case KI_ZFIOMT:
+ # Magtape driver.
+ iferr (call ks_zfiomt (in, out, iobuf, len_iobuf))
+ break
+ else
+ next
+
+ default:
+ # If we receive an illegal opcode on the channel shut the
+ # server down immediately, as communications have almost
+ # certainly been irrecoverably corrupted. We should probably
+ # go one step further and compute a checksum on the packet
+ # header.
+
+ call ks_error (opcode, "illegal opcode on channel")
+ }
+
+ # Transmit response packet back to host. Shutdown if there is
+ # an i/o error on the socket.
+reply_
+ if (debug == YES) {
+ call fprintf (spy, "status = %d\n")
+ call pargi (status)
+ call flush (spy)
+ }
+
+ p_arg[1] = status
+ if (ks_send (out, opcode, subcode) == ERR)
+ break
+ }
+
+ call mfree (iobuf, TY_CHAR)
+
+ if (debug == YES) {
+ call fprintf (spy, "kernel server, normal exit\n")
+ call flush (spy)
+ }
+end
+
+
+# KS_ZFIOBF -- I/O to the class of binary file devices. The i/o request is
+# passed in the KII common (unpacked packet from the host via the network).
+
+procedure ks_zfiobf (in, out, iobuf, len_iobuf, bfdd)
+
+int in, out # input and output channels to host
+pointer iobuf # scratch i/o buffer
+int len_iobuf # current length of buffer
+int bfdd[ARB] # loaded device drivers
+
+long lval, ks_maxbufsize
+int dd, status, nchars, arg1, arg2, arg3
+char osfn[SZ_PATHNAME], temp[SZ_PATHNAME]
+errchk realloc
+int ks_send()
+include "kii.com"
+define fatal_ 91
+
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ # Determine the table offset of the device driver in the table of all
+ # loaded binary file device drivers. The device driver opcodes are
+ # assigned sequentially and KI_ZFIOBF is always first.
+
+ dd = (p_opcode - KI_ZFIOBF) * LEN_BFDRIVER + 1
+
+ # Make sure the iobuffer is large enough. If a large enough buffer
+ # cannot be allocated something is very wrong and the server shuts
+ # down.
+
+ if (p_subcode == BF_ARD || p_subcode == BF_AWR) {
+ nchars = (p_arg[2] + SZB_CHAR-1) / SZB_CHAR
+ if (len_iobuf < nchars) {
+ call realloc (iobuf, nchars, TY_CHAR)
+ len_iobuf = nchars
+ }
+ }
+
+ arg1 = p_arg[1]
+ arg2 = p_arg[2]
+ arg3 = p_arg[3]
+
+ switch (p_subcode) {
+ case BF_OPN:
+ # Open a binary file.
+
+ if (debug == YES) {
+ call fprintf (spy, "open binary file `%s', mode %d\n")
+ call pargstr (p_sbuf[arg1])
+ call pargi (arg2)
+ }
+
+ # Do not map the filename strings of special devices, since the
+ # syntax of such strings may bear no resemblance to that of an
+ # ordinary filename.
+
+ status = OK
+ if (p_opcode == KI_ZFIOBF) {
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn, SZ_PATHNAME))
+ status = ERR
+ } else
+ call strpak (p_sbuf[arg1], osfn, SZ_PATHNAME)
+
+ if (status != ERR)
+ call zcall3 (ZOPNBF(dd), osfn, arg2, status)
+
+ case BF_CLS:
+ # Close a binary file.
+
+ if (debug == YES) {
+ call fprintf (spy, "close %d\n")
+ call pargi (arg1)
+ }
+
+ call zcall2 (ZCLSBF(dd), arg1, status)
+
+ case BF_ARD:
+ # Read from a binary file. The read must be performed in one
+ # operation to preserve the record size. Overlapped i/o is
+ # provided by the dual process nature of the read; the actual
+ # device read is not performed asynchronously since we must
+ # complete each request before processing the next one.
+
+ if (debug == YES) {
+ call fprintf (spy, "aread (%d, %d, %d)\n")
+ call pargi (arg1)
+ call pargi (arg2)
+ call pargi (arg3)
+ }
+
+ # Read the data.
+ call zcall4 (ZARDBF(dd), arg1, Memc[iobuf], arg2, arg3)
+ call zcall2 (ZAWTBF(dd), arg1, status)
+
+ # Send the ZAWT packet to the host followed by the data block.
+ # The next operation performed by the host on the channel MUST
+ # be completion of the i/o transfer, but the host can go off and
+ # do other things before completing the transfer.
+
+ p_arg[1] = status
+ if (ks_send (out, p_opcode, BF_AWT) == ERR)
+ goto fatal_
+ if (status > 0) {
+ call zawrks (out, Memc[iobuf], status, 0)
+ call zawtks (out, status)
+ if (status <= 0)
+ goto fatal_
+ }
+
+ if (debug == YES) {
+ call fprintf (spy, "status %d\n")
+ call pargi (status)
+ }
+
+ return
+
+ case BF_AWR:
+ # Write to a binary file. For maximum performance the write
+ # operation is half duplex, i.e., the ZAWT operation is ignored
+ # for writes to a binary file over the network. If a write
+ # error occurs when writing to the physical device we shutdown
+ # the entire kernel process, causing a FIO write error in the
+ # host if the next kernel server operation is another write to
+ # the same channel. This may cause ficticious i/o errors on
+ # other channels as well, but the performance gain is worth it.
+
+ if (debug == YES) {
+ call fprintf (spy, "awrite (%d, %d, %d)\n")
+ call pargi (arg1)
+ call pargi (arg2)
+ call pargi (arg3)
+ }
+
+ # Read the data from the host.
+ call zardks (in, Memc[iobuf], arg2, 0)
+ call zawtks (in, status)
+ if (debug == YES) {
+ call fprintf (spy, "read net status %d\n")
+ call pargi (status)
+ }
+ if (status != arg2)
+ goto fatal_
+
+ # Write the data to the output device.
+ # TODO - delay the call to zawtbf to overlap i/o even further.
+
+ call zcall4 (ZAWRBF(dd), arg1, Memc[iobuf], arg2, arg3)
+ call zcall2 (ZAWTBF(dd), arg1, status)
+ if (debug == YES) {
+ call fprintf (spy, "write device status %d\n")
+ call pargi (status)
+ }
+ if (status != arg2)
+ goto fatal_
+
+ return
+
+ case BF_AWT:
+ # Wait for i/o on the device channel. Not implemented as a
+ # discreen kernel server operation.
+
+ status = ERR
+
+ case BF_STT:
+ # Get channel status.
+ call zcall3 (ZSTTBF(dd), arg1, arg2, lval)
+
+ # The max transfer size for a binary device is limited by the
+ # network interface as well as the device.
+
+ if (arg2 == FSTT_MAXBUFSIZE || arg2 == FSTT_OPTBUFSIZE) {
+ call zsttks (out, FSTT_MAXBUFSIZE, ks_maxbufsize)
+ if (lval == 0)
+ lval = ks_maxbufsize
+ else if (ks_maxbufsize > 0)
+ lval = min (ks_maxbufsize, lval)
+ }
+ status = lval
+
+ default:
+ status = ERR
+ }
+
+ # Return a status packet to the host if the operation was not a read
+ # or a write.
+
+ if (debug == YES) {
+ call fprintf (spy, "status %d\n")
+ call pargi (status)
+ }
+
+ p_arg[1] = status
+ if (ks_send (out, p_opcode, p_subcode) != ERR)
+ return
+
+fatal_
+ call ks_error (1, "kernel server binary file i/o error")
+end
+
+
+# KS_ZFIOTX -- I/O to the class of text file devices. The i/o request is
+# passed in the KII common (unpacked packet from the host via the network).
+# Text file i/o is buffered by the KI, reading and writing an integral
+# number of full lines of text in each transfer.
+
+procedure ks_zfiotx (in, out, iobuf, len_iobuf, txdd)
+
+int in, out # input and output channels to host
+pointer iobuf # scratch i/o buffer (not used)
+int len_iobuf # current length of buffer (not used)
+int txdd[ARB] # loaded device drivers
+
+long lval, reclen
+bool buffer_full
+pointer rp, nextrec
+char osfn[SZ_PATHNAME], temp[SZ_PATHNAME]
+int dd, status, maxch, nchars, arg1, arg2, arg3
+
+int ks_send()
+long ki_decode()
+include "kii.com"
+define fatal_ 91
+
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ # Determine the table offset of the device driver in the table of all
+ # loaded text file device drivers. The device driver opcodes are
+ # assigned sequentially and KI_ZFIOTX is always first.
+
+ dd = (p_opcode - KI_ZFIOTX) * LEN_TXDRIVER + 1
+
+ arg1 = p_arg[1]
+ arg2 = p_arg[2]
+ arg3 = p_arg[3]
+
+ switch (p_subcode) {
+ case TX_OPN:
+ # Open a text file.
+
+ if (debug == YES) {
+ call fprintf (spy, "open text file `%s', mode %d\n")
+ call pargstr (p_sbuf[arg1])
+ call pargi (arg2)
+ }
+
+ call strcpy (p_sbuf[arg1], temp, SZ_PATHNAME)
+ iferr (call ks_fmapfn (temp, osfn, SZ_PATHNAME))
+ status = ERR
+ else
+ call zcall3 (ZOPNTX(dd), osfn, arg2, status)
+
+ case TX_CLS:
+ # Close a binary file.
+
+ if (debug == YES) {
+ call fprintf (spy, "close text file %d\n")
+ call pargi (arg1)
+ }
+
+ call zcall2 (ZCLSTX(dd), arg1, status)
+
+ case TX_GET:
+ # Read from a text file. If the device is an ordinary text file
+ # (device TX) read as many lines of maximum size SZ_LINE as will
+ # fit in the output buffer. If the device is a terminal return
+ # a single line in each call. Each line is returned as a record
+ # with the record length and seek offset of the line included
+ # in the record header (buffering complicates the ZNOTTX function).
+
+ if (debug == YES) {
+ call fprintf (spy, "gettx %d\n")
+ call pargi (arg1)
+ }
+
+ rp = iobuf
+
+ repeat {
+ maxch = min (arg2, SZ_LINE)
+ call zcall2 (ZNOTTX(dd), arg1, lval)
+ call zcall4 (ZGETTX(dd), arg1, Memc[R_DATA(rp)],
+ maxch, status)
+
+ if (status >= 0) {
+ reclen = R_GETRECLEN (status)
+ call ki_encode (reclen, R_RECLEN(rp), NCHARS_INT)
+ call ki_encode (lval, R_SEKOFF(rp), NCHARS_LONG)
+
+ rp = rp + reclen
+ }
+
+ nextrec = rp + R_GETRECLEN (SZ_LINE)
+ buffer_full = (nextrec - iobuf > arg2)
+
+ } until (p_opcode != KI_ZFIOTX || status <= 0 || buffer_full)
+
+ # If the data record is small enough to fit in the packet string
+ # buffer, return it in the packet, else return it as a second
+ # record following the packet.
+
+ if (status == ERR)
+ nchars = ERR
+ else if (status == EOF && rp == iobuf)
+ nchars = EOF
+ else {
+ nchars = rp - iobuf
+ if (nchars <= SZ_SBUF) {
+ call amovc (Memc[iobuf], p_sbuf, nchars)
+ p_sbuflen = nchars
+ }
+ }
+
+ p_arg[1] = nchars
+ if (ks_send (out, p_opcode, p_subcode) == ERR)
+ goto fatal_
+
+ if (nchars > SZ_SBUF) {
+ call chrpak (Memc[iobuf], 1, Memc[iobuf], 1, nchars)
+ call zawrks (out, Memc[iobuf], nchars, long(0))
+ call zawtks (out, status)
+ if (status != nchars)
+ goto fatal_
+ }
+
+ return
+
+ case TX_PUT:
+ # Put a block of data to a text file. If the block is larger than
+ # the packet string buffer it is passed as a second record following
+ # the packet.
+
+ nchars = arg2
+ if (nchars <= SZ_SBUF)
+ call zcall4 (ZPUTTX(dd), arg1, p_sbuf, nchars, status)
+ else {
+ call zardks (in, Memc[iobuf], nchars, long(0))
+ call zawtks (in, status)
+ if (status != nchars)
+ goto fatal_
+
+ call chrupk (Memc[iobuf], 1, Memc[iobuf], 1, nchars)
+ call zcall4 (ZPUTTX(dd), arg1, Memc[iobuf], nchars, status)
+ }
+
+ # If an error occurs writing to a text file close the kernel
+ # server itself down, rather than handshaking on each packet.
+
+ if (status == ERR)
+ goto fatal_
+
+ return
+
+ case TX_FLS:
+ # Flush text file output.
+ call zcall2 (ZFLSTX(dd), arg1, status)
+
+ case TX_SEK:
+ # Seek on a text file.
+ lval = ki_decode (p_sbuf, NCHARS_LONG)
+ call zcall3 (ZSEKTX(dd), arg1, lval, status)
+
+ case TX_NOT:
+ # Note the file position of a text file. The seek offset is
+ # returned encoded as a char sequence in the string buffer to
+ # avoid problems with integer precision.
+
+ call zcall2 (ZNOTTX(dd), arg1, lval)
+ call ki_encode (lval, p_sbuf, NCHARS_LONG)
+ p_sbuflen = NCHARS_LONG
+ status = lval
+
+ case TX_STT:
+ # Get channel status.
+
+ call zcall3 (ZSTTTX(dd), arg1, arg2, lval)
+ call ki_encode (lval, p_sbuf, NCHARS_LONG)
+ p_sbuflen = NCHARS_LONG
+ status = lval
+
+ default:
+ status = ERR
+ }
+
+ # Return a status/data packet to the host if the subcode did not
+ # specify the get or put function.
+
+ if (debug == YES) {
+ call fprintf (spy, "status %d\n")
+ call pargi (status)
+ }
+
+ p_arg[1] = status
+ if (ks_send (out, p_opcode, p_subcode) != ERR)
+ return
+
+fatal_
+ call ks_error (1, "kernel server text file i/o error")
+end
+
+
+# KS_ZFIOMT -- I/O to the magtape device. The i/o request is passed in
+# the KII common (unpacked packet from the host via the network).
+
+procedure ks_zfiomt (in, out, iobuf, len_iobuf)
+
+int in, out # input and output channels to host
+pointer iobuf # scratch i/o buffer
+int len_iobuf # current length of buffer
+
+long lval
+int status, nchars, mode, dc_off, dc_len
+int newfile, arg[MAX_ARGS]
+char drive[SZ_FNAME]
+errchk realloc
+include "kii.com"
+int ks_send()
+define fatal_ 91
+
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ call amovi (p_arg, arg, MAX_ARGS)
+
+ # Make sure the iobuffer is large enough. If a large enough buffer
+ # cannot be allocated something is very wrong and the server shuts
+ # down.
+
+ if (p_subcode == MT_RD || p_subcode == MT_WR) {
+ nchars = (arg[2] + SZB_CHAR-1) / SZB_CHAR
+ if (len_iobuf < nchars) {
+ call realloc (iobuf, nchars, TY_CHAR)
+ len_iobuf = nchars
+ }
+ }
+
+ switch (p_subcode) {
+ case MT_OP:
+ # Open a magtape device.
+
+ mode = arg[2]
+ dc_off = arg[3]
+ dc_len = arg[4]
+ newfile = arg[5]
+
+ # Get the device name string.
+ call strpak (p_sbuf[arg[1]], drive, SZ_PATHNAME)
+
+ # Get the devcap string.
+ if (dc_len > 0 && dc_off == 0) {
+ call zardks (in, Memc[iobuf], dc_len+1, 0)
+ call zawtks (in, status)
+ if (status != dc_len + 1)
+ goto fatal_
+ } else
+ call strpak (p_sbuf[dc_off], Memc[iobuf], len_iobuf)
+
+ if (debug == YES) {
+ call fprintf (spy,
+ "open magtape device `%s', mode=%d, file=%d, devcap=`%s'\n")
+ call pargstr (p_sbuf[arg[1]])
+ call pargi (mode)
+ call pargi (newfile)
+
+ call strupk (Memc[iobuf], Memc[iobuf], len_iobuf)
+ call pargstr (Memc[iobuf])
+ call strpak (Memc[iobuf], Memc[iobuf], len_iobuf)
+ }
+
+ call zzopmt (drive, mode, Memc[iobuf], arg[6], newfile, status)
+ p_arg[2] = newfile
+
+ case MT_CL:
+ # Close a binary file.
+ call zzclmt (arg[1], p_arg[2], status)
+
+ case MT_RD:
+ # Read from a magtape file. The read must be performed in one
+ # operation to preserve the record size. Overlapped i/o is
+ # provided by the dual process nature of the read; the actual
+ # device read is not performed asynchronously since we must
+ # complete each request before processing the next one.
+
+ # Read the data.
+ call zzrdmt (arg[1], Memc[iobuf], arg[2], arg[3])
+ call zzwtmt (arg[1], p_arg[2], status)
+
+ # Send the ZAWT packet to the host followed by the data block.
+ # The next operation performed by the host on the channel MUST
+ # be completion of the i/o transfer, but the host can go off and
+ # do other things before completing the transfer.
+
+ p_arg[1] = status
+ if (ks_send (out, p_opcode, MT_WT) == ERR)
+ goto fatal_
+ if (status > 0) {
+ call zawrks (out, Memc[iobuf], status, 0)
+ call zawtks (out, status)
+ if (status <= 0)
+ goto fatal_
+ }
+
+ return
+
+ case MT_WR:
+ # Write to a magtape file. For maximum performance the write
+ # operation is half duplex, i.e., the ZAWT operation is ignored
+ # for writes to a binary file over the network. If a write
+ # error occurs when writing to the physical device we shutdown
+ # the entire kernel process, causing a FIO write error in the
+ # host if the next kernel server operation is another write to
+ # the same channel. This may cause ficticious i/o errors on
+ # other channels as well, but the performance gain is worth it.
+
+ # Read the data from the host.
+ call zardks (in, Memc[iobuf], arg[2], 0)
+ call zawtks (in, status)
+ if (status != arg[2])
+ goto fatal_
+
+ # Write the data to the output device.
+ # TODO - delay the call to zawtbf to overlap i/o even further.
+
+ call zzwrmt (arg[1], Memc[iobuf], arg[2], arg[3])
+ call zzwtmt (arg[1], p_arg[2], status)
+ if (status != arg[2])
+ goto fatal_
+
+ return
+
+ case MT_WT:
+ # Wait for i/o on the device channel. Not implemented as a
+ # discreet kernel server operation; for a read the wait status
+ # is returned with the data, and for a write we assume the normal
+ # status and break the connection if the assumption is false.
+
+ status = ERR
+
+ case MT_ST:
+ # Get device status.
+ call zzstmt (arg[1], arg[2], lval)
+ status = lval
+
+ case MT_RW:
+ # Rewind a drive.
+ dc_off = p_arg[2]
+ dc_len = p_arg[3]
+
+ # Get the device name string.
+ call strpak (p_sbuf[arg[1]], drive, SZ_PATHNAME)
+
+ # Get the devcap string.
+ if (dc_len > 0 && dc_off == 0) {
+ call zardks (in, Memc[iobuf], dc_len+1, 0)
+ call zawtks (in, status)
+ if (status != dc_len + 1)
+ goto fatal_
+ } else
+ call strpak (p_sbuf[dc_off], Memc[iobuf], len_iobuf)
+
+ call zzrwmt (drive, Memc[iobuf], status)
+
+ default:
+ status = ERR
+ }
+
+ # Return a status packet to the host if the operation was not a read
+ # or a write.
+
+ if (debug == YES) {
+ call fprintf (spy, "status %d\n")
+ call pargi (status)
+ }
+
+ p_arg[1] = status
+ if (ks_send (out, p_opcode, p_subcode) != ERR)
+ return
+
+fatal_
+ call ks_error (1, "kernel server magtape i/o error")
+end
+
+
+# KS_ERROR -- Spool error message if debug is enabled, then call error
+# to kill kernel server.
+
+procedure ks_error (errcode, errmsg)
+
+int errcode
+char errmsg[ARB]
+
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ if (debug == YES) {
+ call fprintf (spy, "ERROR (%d, `%s')\n")
+ call pargi (errcode)
+ call pargstr (errmsg)
+ }
+
+ call error (errcode, errmsg)
+end
+
+
+# KS_LOADBF -- Load the binary file drivers. The order in which the driver
+# entry points are loaded must agree with the defines at the head of this file.
+
+procedure ks_loadbf (bfdd)
+
+int bfdd[ARB] # device table
+int off, locpr()
+extern zopnbf(), zclsbf(), zardbf(), zawrbf(), zawtbf(), zsttbf()
+extern zopnlp(), zclslp(), zardlp(), zawrlp(), zawtlp(), zsttlp()
+extern zopnpl(), zclspl(), zardpl(), zawrpl(), zawtpl(), zsttpl()
+extern zardpr(), zawrpr(), zawtpr(), zsttpr()
+extern zopnsf(), zclssf(), zardsf(), zawrsf(), zawtsf(), zsttsf()
+extern zopngd(), zclsgd(), zardgd(), zawrgd(), zawtgd(), zsttgd()
+
+begin
+ off = (KI_ZFIOBF - KI_ZFIOBF) * LEN_BFDRIVER
+ bfdd[off+1] = locpr (zopnbf)
+ bfdd[off+2] = locpr (zclsbf)
+ bfdd[off+3] = locpr (zardbf)
+ bfdd[off+4] = locpr (zawrbf)
+ bfdd[off+5] = locpr (zawtbf)
+ bfdd[off+6] = locpr (zsttbf)
+
+ off = (KI_ZFIOLP - KI_ZFIOBF) * LEN_BFDRIVER
+ bfdd[off+1] = locpr (zopnlp)
+ bfdd[off+2] = locpr (zclslp)
+ bfdd[off+3] = locpr (zardlp)
+ bfdd[off+4] = locpr (zawrlp)
+ bfdd[off+5] = locpr (zawtlp)
+ bfdd[off+6] = locpr (zsttlp)
+
+ off = (KI_ZFIOPL - KI_ZFIOBF) * LEN_BFDRIVER
+ bfdd[off+1] = locpr (zopnpl)
+ bfdd[off+2] = locpr (zclspl)
+ bfdd[off+3] = locpr (zardpl)
+ bfdd[off+4] = locpr (zawrpl)
+ bfdd[off+5] = locpr (zawtpl)
+ bfdd[off+6] = locpr (zsttpl)
+
+ off = (KI_ZFIOPR - KI_ZFIOBF) * LEN_BFDRIVER
+ bfdd[off+1] = 0
+ bfdd[off+2] = 0
+ bfdd[off+3] = locpr (zardpr)
+ bfdd[off+4] = locpr (zawrpr)
+ bfdd[off+5] = locpr (zawtpr)
+ bfdd[off+6] = locpr (zsttpr)
+
+ off = (KI_ZFIOSF - KI_ZFIOBF) * LEN_BFDRIVER
+ bfdd[off+1] = locpr (zopnsf)
+ bfdd[off+2] = locpr (zclssf)
+ bfdd[off+3] = locpr (zardsf)
+ bfdd[off+4] = locpr (zawrsf)
+ bfdd[off+5] = locpr (zawtsf)
+ bfdd[off+6] = locpr (zsttsf)
+
+ off = (KI_ZFIOGD - KI_ZFIOBF) * LEN_BFDRIVER
+ bfdd[off+1] = locpr (zopngd)
+ bfdd[off+2] = locpr (zclsgd)
+ bfdd[off+3] = locpr (zardgd)
+ bfdd[off+4] = locpr (zawrgd)
+ bfdd[off+5] = locpr (zawtgd)
+ bfdd[off+6] = locpr (zsttgd)
+end
+
+
+# KS_LOADTX -- Load the text file drivers. The order in which the driver
+# entry points are loaded must agree with the defines at the head of this file.
+
+procedure ks_loadtx (txdd)
+
+int txdd[ARB] # device table
+int off, locpr()
+extern zopntx(), zclstx(), zgettx(), zputtx(), zflstx(), zsektx(), znottx(),
+ zstttx()
+extern zopnty(), zclsty(), zgetty(), zputty(), zflsty(), zsekty(), znotty(),
+ zsttty()
+
+begin
+ off = (KI_ZFIOTX - KI_ZFIOTX) * LEN_TXDRIVER
+ txdd[off+1] = locpr (zopntx)
+ txdd[off+2] = locpr (zclstx)
+ txdd[off+3] = locpr (zgettx)
+ txdd[off+4] = locpr (zputtx)
+ txdd[off+5] = locpr (zflstx)
+ txdd[off+6] = locpr (zsektx)
+ txdd[off+7] = locpr (znottx)
+ txdd[off+8] = locpr (zstttx)
+
+ off = (KI_ZFIOTY - KI_ZFIOTX) * LEN_TXDRIVER
+ txdd[off+1] = locpr (zopnty)
+ txdd[off+2] = locpr (zclsty)
+ txdd[off+3] = locpr (zgetty)
+ txdd[off+4] = locpr (zputty)
+ txdd[off+5] = locpr (zflsty)
+ txdd[off+6] = locpr (zsekty)
+ txdd[off+7] = locpr (znotty)
+ txdd[off+8] = locpr (zsttty)
+end
+
+
+# KS_SEND -- Encode the packet in the kii common in a machine independent form
+# and send it over the network.
+
+int procedure ks_send (server, opcode, subcode)
+
+int server # channel to host
+int opcode # function opcode
+int subcode # function subcode (for drivers)
+
+int status
+include "kii.com"
+
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ p_opcode = opcode
+ p_subcode = subcode
+
+ # Encode the packet in machine independent form, i.e., LEN_INTFIELDS
+ # 32 bit MII integers followed by p_sbuflen chars, one char per byte.
+
+ call miipak32 (FIRSTINTFIELD, p_packet, LEN_INTFIELDS, TY_INT)
+ call chrpak (p_sbuf, 1, p_packet, LEN_INTFIELDS * 4 + 1,
+ min (SZ_SBUF, p_sbuflen + 1))
+
+ # Transmit the packet.
+ call zawrks (server, p_packet, SZB_PACKET, long(0))
+ call zawtks (server, status)
+
+ if (debug == YES) {
+ call fprintf (spy, "ks_send: status=%d\n");call pargi (status)
+ }
+
+ return (status)
+end
+
+
+# KS_RECEIVE -- Read a machine independent KII packet from the network
+# interface and decode it into the internal, machine dependent form in the
+# kii common. This procedure differs from the procedure KI_RECEIVE in
+# that it does not verify the opcode and subcode of the received packet.
+
+int procedure ks_receive (server)
+
+int server # os channel to server process
+int status
+include "kii.com"
+
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ # Read the packet.
+ # [DEBUG]: call zzrdks (server, p_packet, SZB_PACKET, long(0))
+
+ call zardks (server, p_packet, SZB_PACKET, long(0))
+ call zawtks (server, status)
+
+ if (debug == YES && status <= 0) {
+ call fprintf (spy, "ERROR: ks_receive: status=%d\n")
+ call pargi (status)
+ }
+
+ if (status <= 0)
+ return (status)
+
+ # The encoded packet consists of LEN_INTFIELDS 32 bit MII integers
+ # followed by p_sbuflen chars, one char per byte.
+
+ call miiupk32 (p_packet, FIRSTINTFIELD, LEN_INTFIELDS, TY_INT)
+ call chrupk (p_packet, LEN_INTFIELDS * 4 + 1, p_sbuf, 1,
+ min (SZ_SBUF, p_sbuflen + 1))
+
+ if (debug == YES) {
+ call fprintf (spy, "ks_receive: status=%d\n") ; call pargi (status)
+ }
+
+ return (status)
+end
+
+
+# KS_FMAPFN -- Equivalent functionality of FMAPFN but with debug output.
+
+procedure ks_fmapfn (vfn, osfn, maxch)
+
+char vfn[ARB] # filename to be mapped
+char osfn[maxch] # packed output OS filename
+int maxch # max chars out
+
+char upk_osfn[SZ_FNAME]
+errchk fmapfn
+int debug, spy
+common /dbgcom/ debug, spy
+
+begin
+ call fmapfn (vfn, osfn, maxch)
+
+ if (debug == YES) {
+ call strupk (osfn, upk_osfn, SZ_FNAME)
+
+ call fprintf (spy, "`%s' -> `%s'\n")
+ call pargstr (vfn)
+ call pargstr (upk_osfn)
+ }
+end
+
+
+procedure ks_op2str (opcode, subcode, o_str, s_str)
+
+int opcode #i opcode
+int subcode #i opcode
+char o_str[ARB] #o string containing opcode instruction
+char s_str[ARB] #o string containing subcode instruction
+
+begin
+ switch (opcode) {
+ case KI_ENVINIT: call strcpy ("KI_ENVINIT", o_str, SZ_LINE)
+ case KI_SETROOT: call strcpy ("KI_SETROOT", o_str, SZ_LINE)
+ case KI_ZOSCMD: call strcpy ("KI_OSCMD", o_str, SZ_LINE)
+ case KI_FMAPFN: call strcpy ("KI_FMAPFN", o_str, SZ_LINE)
+
+ case KI_ZFACSS: call strcpy ("KI_ZFACSS", o_str, SZ_LINE)
+ case KI_ZFALOC: call strcpy ("KI_ZFALOC", o_str, SZ_LINE)
+ case KI_ZFCHDR: call strcpy ("KI_ZFCHDR", o_str, SZ_LINE)
+ case KI_ZFDELE: call strcpy ("KI_ZFDELE", o_str, SZ_LINE)
+ case KI_ZFINFO: call strcpy ("KI_ZFINFO", o_str, SZ_LINE)
+ case KI_ZFGCWD: call strcpy ("KI_ZFGCWD", o_str, SZ_LINE)
+ case KI_ZFMKCP: call strcpy ("KI_ZFMKCP", o_str, SZ_LINE)
+ case KI_ZFMKDR: call strcpy ("KI_ZFMKDR", o_str, SZ_LINE)
+ case KI_ZFPATH: call strcpy ("KI_ZFPATH", o_str, SZ_LINE)
+ case KI_ZFPROT: call strcpy ("KI_ZFPROT", o_str, SZ_LINE)
+ case KI_ZFRNAM: call strcpy ("KI_ZFRNAM", o_str, SZ_LINE)
+ case KI_ZFRMDR: call strcpy ("KI_ZFRMDR", o_str, SZ_LINE)
+ case KI_ZFSUBD: call strcpy ("KI_ZFSUBD", o_str, SZ_LINE)
+ case KI_ZDVALL: call strcpy ("KI_ZDVALL", o_str, SZ_LINE)
+ case KI_ZDVOWN: call strcpy ("KI_ZDVOWN", o_str, SZ_LINE)
+ case KI_ZFUTIM: call strcpy ("KI_ZFUTIM", o_str, SZ_LINE)
+
+ case KI_ZOPDIR: call strcpy ("KI_ZOPDIR", o_str, SZ_LINE)
+ case KI_ZCLDIR: call strcpy ("KI_ZCLDIR", o_str, SZ_LINE)
+ case KI_ZGFDIR: call strcpy ("KI_ZGFDIR", o_str, SZ_LINE)
+
+ case KI_ZOPDPR: call strcpy ("KI_ZOPDPR", o_str, SZ_LINE)
+ case KI_ZCLDPR: call strcpy ("KI_ZCLDPR", o_str, SZ_LINE)
+ case KI_ZOPCPR: call strcpy ("KI_ZOPCPR", o_str, SZ_LINE)
+ case KI_ZCLCPR: call strcpy ("KI_ZCLCPR", o_str, SZ_LINE)
+ case KI_ZINTPR: call strcpy ("KI_ZINTPR", o_str, SZ_LINE)
+
+ # Device driver opcodes.
+ case KI_ZFIOBF: call strcpy ("KI_ZFIOBF", o_str, SZ_LINE)
+ case KI_ZFIOLP: call strcpy ("KI_ZFIOLP", o_str, SZ_LINE)
+ case KI_ZFIOPL: call strcpy ("KI_ZFIOPL", o_str, SZ_LINE)
+ case KI_ZFIOPR: call strcpy ("KI_ZFIOPR", o_str, SZ_LINE)
+ case KI_ZFIOSF: call strcpy ("KI_ZFIOSF", o_str, SZ_LINE)
+ case KI_ZFIOGD: call strcpy ("KI_ZFIOGD", o_str, SZ_LINE)
+
+ case KI_ZFIOTX: call strcpy ("KI_ZFIOTX", o_str, SZ_LINE)
+ case KI_ZFIOTY: call strcpy ("KI_ZFIOTY", o_str, SZ_LINE)
+
+ case KI_ZFIOMT: call strcpy ("KI_ZFIOMT", o_str, SZ_LINE)
+
+ default: call strcpy ("", o_str, SZ_LINE)
+ }
+
+
+ # Now convert the subcode if needed.
+ call aclrc (s_str, SZ_LINE)
+ if (opcode >= KI_ZFIOBF && opcode <= KI_ZFIOGD) {
+ switch (subcode) {
+ case BF_OPN: call strcpy ("BF_OPN", s_str, SZ_LINE)
+ case BF_CLS: call strcpy ("BF_CLS", s_str, SZ_LINE)
+ case BF_ARD: call strcpy ("BF_ARD", s_str, SZ_LINE)
+ case BF_AWR: call strcpy ("BF_AWR", s_str, SZ_LINE)
+ case BF_AWT: call strcpy ("BF_AWT", s_str, SZ_LINE)
+ case BF_STT: call strcpy ("BF_STT", s_str, SZ_LINE)
+ default: call strcpy ("", s_str, SZ_LINE)
+ }
+
+ } else if (opcode >= KI_ZFIOTX || opcode <= KI_ZFIOTY) {
+ switch (subcode) {
+ case TX_OPN: call strcpy ("TX_OPN", s_str, SZ_LINE)
+ case TX_CLS: call strcpy ("TX_CLS", s_str, SZ_LINE)
+ case TX_GET: call strcpy ("TX_GET", s_str, SZ_LINE)
+ case TX_PUT: call strcpy ("TX_PUT", s_str, SZ_LINE)
+ case TX_FLS: call strcpy ("TX_FLS", s_str, SZ_LINE)
+ case TX_SEK: call strcpy ("TX_SEK", s_str, SZ_LINE)
+ case TX_NOT: call strcpy ("TX_NOT", s_str, SZ_LINE)
+ case TX_STT: call strcpy ("TX_STT", s_str, SZ_LINE)
+ default: call strcpy ("", s_str, SZ_LINE)
+ }
+
+ } else if (opcode >= KI_ZFIOMT) {
+ switch (subcode) {
+ case MT_OP: call strcpy ("MT_OP", s_str, SZ_LINE)
+ case MT_CL: call strcpy ("MT_CL", s_str, SZ_LINE)
+ case MT_RD: call strcpy ("MT_RD", s_str, SZ_LINE)
+ case MT_WR: call strcpy ("MT_WR", s_str, SZ_LINE)
+ case MT_WT: call strcpy ("MT_WT", s_str, SZ_LINE)
+ case MT_ST: call strcpy ("MT_ST", s_str, SZ_LINE)
+ case MT_RW: call strcpy ("MT_RW", s_str, SZ_LINE)
+ default: call strcpy ("", s_str, SZ_LINE)
+ }
+ }
+
+end
diff --git a/sys/ki/kbzard.x b/sys/ki/kbzard.x
new file mode 100644
index 00000000..7370f7f9
--- /dev/null
+++ b/sys/ki/kbzard.x
@@ -0,0 +1,60 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KB_ZARD -- Asynchronous read from a binary device. We are called only if
+# the device does not reside on the local node. In this implementation
+# these reads are not actually asynchronous. This is possible but more
+# complex to implement than I wanted to get into at this time, particularly
+# since FIO is not yet fully asynchronous. The problem is that a node
+# channel may be used to multiplex any number of requests to the remote
+# node process. If an asynchronous read is pending this must be detected
+# and the read completed before processing any other requests.
+
+procedure kb_zard (device, chan, obuf, max_bytes, loffset)
+
+int device # device driver code
+int chan # channel assigned device
+char obuf[max_bytes] # receives data
+int max_bytes # max bytes to read
+long loffset # file offset
+
+int server, status
+int ki_send(), ki_receive()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = k_node[chan]
+
+ if (max_bytes <= 0) {
+ k_status[chan] = 0
+ return
+ }
+
+ # Send the request to initiate the read.
+
+ p_arg[1] = k_oschan[chan]
+ p_arg[2] = max_bytes
+ p_arg[3] = loffset
+
+ if (ki_send (server, device, BF_ARD) == ERR) {
+ status = ERR
+ } else {
+ # Wait for the ZAWT packet.
+ if (ki_receive (server, device, BF_AWT) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+
+ # Read the data block (if any) directly into caller's buffer.
+ if (status > 0) {
+ call ks_aread (server, obuf, status)
+ call ks_await (server, status)
+ }
+ }
+
+ k_status[chan] = status
+end
diff --git a/sys/ki/kbzawr.x b/sys/ki/kbzawr.x
new file mode 100644
index 00000000..406c14ba
--- /dev/null
+++ b/sys/ki/kbzawr.x
@@ -0,0 +1,47 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KB_ZAWR -- Asynchronous write to a binary device. We are called only if
+# the device does not reside on the local node.
+
+procedure kb_zawr (device, chan, ibuf, nbytes, loffset)
+
+int device # device driver code
+int chan # channel assigned device
+char ibuf[nbytes] # receives data
+int nbytes # number of bytes to write
+long loffset # file offset
+
+int server
+int ki_send()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = k_node[chan]
+
+ if (nbytes <= 0) {
+ k_status[chan] = 0
+ return
+ }
+
+ # Send the request followed by the data block. We must wait for the
+ # write into the network channel to complete since the channel is
+ # multiplexed. Note that this is not the same as waiting for the
+ # data transfer to the physical device to complete; that transfer is
+ # at least partially asynchronous.
+
+ p_arg[1] = k_oschan[chan]
+ p_arg[2] = nbytes
+ p_arg[3] = loffset
+
+ if (ki_send (server, device, BF_AWR) == ERR)
+ k_status[chan] = ERR
+ else {
+ call ks_awrite (server, ibuf, nbytes)
+ call ks_await (server, k_status[chan])
+ }
+end
diff --git a/sys/ki/kbzawt.x b/sys/ki/kbzawt.x
new file mode 100644
index 00000000..e0d5a9d6
--- /dev/null
+++ b/sys/ki/kbzawt.x
@@ -0,0 +1,43 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include "ki.h"
+
+# KB_ZAWT -- Wait for i/o to a binary file. Called after an asynchronous read
+# or write has been issued on a channel. We are not called unless the device
+# does not reside on the local node. If the last i/o transfer was a read then
+# the ZAWT packet will be followed by the data which we must copy into the
+# callers buffer, using the pointer saved when the read was posted. If the
+# last i/o operation was a write then we assume that the write was successful
+# and merely return the number of bytes written (error checking occurs
+# elsewhere).
+#
+# read: sendpkt, rcvpkt, readdata
+# write: sendpkt, senddata [nothing]
+#
+# (zard|zawr) (zawt)
+#
+# Note that the ZAWT function is processed locally in the case of a write,
+# rather than being passed to the kernel server. This makes file write
+# operations a pipelined operation, significantly increasing the opportunity
+# for overlapped execution and increasing the data bandwidth. If the number
+# of bytes transferred to the remote device is not what is requested then the
+# remote kernel server will close the entire channel down (not just the
+# multiplexed channel for the device), causing a ZAWRKS error in the local
+# process.
+#
+# NOTE -- disregard the above regarding asynchronous reads. ZARD is currently
+# implemented as a synchronous read. The comments are retained here to show
+# how to speed up reads when the i/o system is made fully asynchronous.
+
+procedure kb_zawt (device, chan, status)
+
+int device # device driver code
+int chan # channel assigned device
+int status # receives nbytes transferred or ERR
+
+include "kichan.com"
+
+begin
+ status = k_status[chan]
+end
diff --git a/sys/ki/kbzcls.x b/sys/ki/kbzcls.x
new file mode 100644
index 00000000..afb1f348
--- /dev/null
+++ b/sys/ki/kbzcls.x
@@ -0,0 +1,37 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KB_ZCLS -- Close a binary device. We are called only if the device does not
+# reside on the local node.
+
+procedure kb_zcls (device, chan, status)
+
+int device # device driver code
+int chan # channel assigned device
+int status # receives ok|err
+
+int server
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+
+ # If we receive error on the KS channel when trying to close a file,
+ # it is most likely due to a previous i/o error on the channel. Do
+ # not return error here because we are probably being called during
+ # error recovery to free the logical channel, and if we return error
+ # the real error will be hidden.
+
+ if (ki_sendrcv (server, device, BF_CLS) == ERR)
+ status = OK
+ else
+ status = p_arg[1]
+
+ call ki_freechan (chan)
+end
diff --git a/sys/ki/kbzopn.x b/sys/ki/kbzopn.x
new file mode 100644
index 00000000..8a332b47
--- /dev/null
+++ b/sys/ki/kbzopn.x
@@ -0,0 +1,30 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KB_ZOPN -- Open a binary device. We are called only if the device does not
+# reside on the local node.
+
+procedure kb_zopn (device, osfn, mode, chan)
+
+int device # device driver code
+char osfn[ARB] # packed os filename
+int mode # access mode
+int chan # receives assigned channel
+
+int server
+int ki_connect(), ki_sendrcv(), ki_getchan()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+ p_arg[2] = mode
+
+ if (ki_sendrcv (server, device, BF_OPN) == ERR)
+ chan = ERR
+ else if (p_arg[1] == ERR)
+ chan = ERR
+ else
+ chan = ki_getchan (server, p_arg[1])
+end
diff --git a/sys/ki/kbzstt.x b/sys/ki/kbzstt.x
new file mode 100644
index 00000000..0610dd7f
--- /dev/null
+++ b/sys/ki/kbzstt.x
@@ -0,0 +1,48 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <fio.h>
+include "ki.h"
+
+# KB_ZSTT -- Get file status on a binary device. We are called only if the
+# device does not reside on the local node.
+
+procedure kb_zstt (device, chan, what, lvalue)
+
+int device # device driver code
+int chan # channel assigned device
+int what # file parameter to be returned
+long lvalue # receives the parameter value
+
+int server, ks_maxbufsize
+int ki_sendrcv()
+include "kichan.com"
+include "kinode.com"
+include "kii.com"
+data ks_maxbufsize /-1/
+
+begin
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+ p_arg[2] = what
+
+ if (ki_sendrcv (server, device, BF_STT) == ERR)
+ lvalue = ERR
+ else {
+ lvalue = p_arg[1]
+
+ # The maximum buffer (transfer) size for a device is determined
+ # by the the network interface or by the device, whichever is
+ # smaller.
+
+ if (what == FSTT_MAXBUFSIZE || what == FSTT_OPTBUFSIZE) {
+ if (ks_maxbufsize < 0)
+ call zsttks (n_kschan[server], FSTT_MAXBUFSIZE, ks_maxbufsize)
+ if (lvalue == 0)
+ lvalue = ks_maxbufsize
+ else if (ks_maxbufsize > 0)
+ lvalue = min (lvalue, ks_maxbufsize)
+ }
+ }
+end
diff --git a/sys/ki/kclcpr.x b/sys/ki/kclcpr.x
new file mode 100644
index 00000000..b3822c63
--- /dev/null
+++ b/sys/ki/kclcpr.x
@@ -0,0 +1,50 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KCLCPR -- Close a connected subprocess.
+
+procedure kclcpr (pid, exit_status)
+
+int pid # channel descriptor
+int exit_status # exit status of the job
+
+int server, inchan, outchan
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (pid <= 0) {
+ exit_status = OK
+ return
+ }
+
+ server = k_node[pid]
+
+ if (server == NULL) {
+ call zclcpr (k_oschan[pid], exit_status)
+ } else {
+ p_arg[1] = k_oschan[pid]
+ p_sbuflen = 0
+
+ if (ki_sendrcv (server, KI_ZCLCPR, 0) == ERR)
+ exit_status = ERR
+ else
+ exit_status = p_arg[1]
+ }
+
+ # The channel descriptor numbers of the two cds used for the i/o
+ # streams are encoded in the k_status field of the PID cd.
+
+ inchan = k_status[pid] / MAX_CHANNELS
+ outchan = mod (k_status[pid], MAX_CHANNELS)
+
+ # Free the 3 channel descriptors used by the subprocess.
+ call ki_freechan (pid)
+ call ki_freechan (inchan)
+ call ki_freechan (outchan)
+end
diff --git a/sys/ki/kcldir.x b/sys/ki/kcldir.x
new file mode 100644
index 00000000..8f85f82f
--- /dev/null
+++ b/sys/ki/kcldir.x
@@ -0,0 +1,44 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KCLDIR -- Close a directory file.
+
+procedure kcldir (chan, status)
+
+int chan # channel descriptor
+int status # answer; ok or err
+
+int server
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ server = k_node[chan]
+
+ if (server == NULL) {
+ call zcldir (k_oschan[chan], status)
+
+ } else {
+ p_arg[1] = k_oschan[chan]
+ p_sbuflen = 0
+
+ if (ki_sendrcv (server, KI_ZCLDIR, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+
+ call mfree (k_bufp[chan], TY_STRUCT)
+ }
+
+ call ki_freechan (chan)
+end
diff --git a/sys/ki/kcldpr.x b/sys/ki/kcldpr.x
new file mode 100644
index 00000000..43060701
--- /dev/null
+++ b/sys/ki/kcldpr.x
@@ -0,0 +1,44 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KCLDPR -- Close a detached process.
+
+procedure kcldpr (jobcode, killflag, exit_status)
+
+int jobcode # channel descriptor
+int killflag # kill job or just wait for it to terminate
+int exit_status # exit status of the job
+
+int server
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (jobcode <= 0) {
+ exit_status = OK
+ return
+ }
+
+ server = k_node[jobcode]
+
+ if (server == NULL) {
+ call zcldpr (k_oschan[jobcode], killflag, exit_status)
+
+ } else {
+ p_arg[1] = k_oschan[jobcode]
+ p_arg[2] = killflag
+ p_sbuflen = 0
+
+ if (ki_sendrcv (server, KI_ZCLDPR, 0) == ERR)
+ exit_status = ERR
+ else
+ exit_status = p_arg[1]
+ }
+
+ call ki_freechan (jobcode)
+end
diff --git a/sys/ki/kdvall.x b/sys/ki/kdvall.x
new file mode 100644
index 00000000..a198df4f
--- /dev/null
+++ b/sys/ki/kdvall.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KDVALL -- Allocate/deallocate a device.
+
+procedure kdvall (device, allflag, status)
+
+char device[ARB] # device name or alias list
+int allflag # flag: allocate=1, deallocate=0
+int status # return status
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (device)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zdvall (p_sbuf, allflag, status)
+
+ } else {
+ p_arg[2] = allflag
+ if (ki_sendrcv (server, KI_ZDVALL, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kdvown.x b/sys/ki/kdvown.x
new file mode 100644
index 00000000..0b5180a7
--- /dev/null
+++ b/sys/ki/kdvown.x
@@ -0,0 +1,37 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KDVOWN -- Query device allocation; return the owner name if the device is
+# allocated to someone else.
+
+procedure kdvown (device, owner, maxch, status)
+
+char device[ARB] # packed device name string
+char owner[ARB] # receives owner name string
+int maxch # max chars out
+int status # allocation status (<xalloc.h>)
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (device)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zdvown (p_sbuf, owner, maxch, status)
+
+ } else {
+ p_arg[2] = maxch
+ if (ki_sendrcv (server, KI_ZDVOWN, 0) == ERR) {
+ owner[1] = EOS
+ status = ERR
+ } else {
+ status = p_arg[1]
+ call strpak (p_sbuf, owner, maxch)
+ }
+ }
+end
diff --git a/sys/ki/kfacss.x b/sys/ki/kfacss.x
new file mode 100644
index 00000000..5634e099
--- /dev/null
+++ b/sys/ki/kfacss.x
@@ -0,0 +1,35 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KFACSS -- Determine the accessibility and type of a file.
+
+procedure kfacss (osfn, mode, type, status)
+
+char osfn[ARB] # packed os filename
+int mode # access mode or null if don't care
+int type # file type or null if don't care
+int status # answer; yes or no
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfacss (p_sbuf, mode, type, status)
+
+ } else {
+ p_arg[2] = mode
+ p_arg[3] = type
+
+ if (ki_sendrcv (server, KI_ZFACSS, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kfaloc.x b/sys/ki/kfaloc.x
new file mode 100644
index 00000000..4ba8d041
--- /dev/null
+++ b/sys/ki/kfaloc.x
@@ -0,0 +1,33 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KFALOC -- Create and preallocate space for a binary file.
+
+procedure kfaloc (osfn, nbytes, status)
+
+char osfn[ARB] # packed os filename
+int nbytes # nbytes of storage to allocate
+int status # answer; ok or err
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfaloc (p_sbuf, nbytes, status)
+
+ } else {
+ p_arg[2] = nbytes
+
+ if (ki_sendrcv (server, KI_ZFALOC, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kfchdr.x b/sys/ki/kfchdr.x
new file mode 100644
index 00000000..2e1b6501
--- /dev/null
+++ b/sys/ki/kfchdr.x
@@ -0,0 +1,61 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include <mach.h>
+include <chars.h>
+include "ki.h"
+
+# KFCHDR -- Change the default directory. The default node is also set if
+# the request is successful.
+
+procedure kfchdr (dirname, status)
+
+char dirname[ARB] # directory name
+int status
+
+pointer sp, fname, defnode
+int server, junk
+int ki_gnode(), ki_connect(), ki_findnode()
+# int ki_sendrcv()
+include "kinode.com"
+include "kii.com"
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (defnode, SZ_ALIAS, TY_CHAR)
+
+ server = ki_connect (dirname)
+
+ if (server == NULL) {
+ # Directory is on the local node.
+
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfchdr (p_sbuf, status)
+
+ } else {
+ # Directory is on a remote node. Pass the node relative chdir
+ # request on to the remote node and set the default node locally
+ # if the request is successful.
+
+ # Does not work yet.
+ #if (ki_sendrcv (server, KI_ZFCHDR, 0) != ERR)
+ # status = p_arg[1]
+ #else
+ # status = ERR
+
+ status = ERR
+ }
+
+ # Update the default node if the change directory request
+ # is successful.
+
+ if (status != ERR) {
+ call strupk (dirname, Memc[fname], SZ_PATHNAME)
+ junk = ki_gnode (Memc[fname], Memc[defnode], junk)
+ call strcpy (Memc[defnode], n_defaultnode, SZ_ALIAS)
+ n_default = ki_findnode (n_defaultnode)
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/ki/kfdele.x b/sys/ki/kfdele.x
new file mode 100644
index 00000000..53e0822a
--- /dev/null
+++ b/sys/ki/kfdele.x
@@ -0,0 +1,30 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KFDELE -- Delete a file.
+
+procedure kfdele (osfn, status)
+
+char osfn[ARB] # packed os filename
+int status # answer; ok or err
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfdele (p_sbuf, status)
+
+ } else {
+ if (ki_sendrcv (server, KI_ZFDELE, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kfgcwd.x b/sys/ki/kfgcwd.x
new file mode 100644
index 00000000..c142eaa8
--- /dev/null
+++ b/sys/ki/kfgcwd.x
@@ -0,0 +1,54 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include <mach.h>
+include <chars.h>
+include "ki.h"
+
+# KFGCWD -- Get the name of the current default directory.
+
+procedure kfgcwd (outstr, maxch, nchars)
+
+char outstr[maxch] # receives pathname of directory
+int maxch # max chars out
+int nchars # length of returned string
+
+int server, op
+int gstrcpy(), ki_sendrcv()
+include "kinode.com"
+include "kii.com"
+define err_ 91
+
+begin
+ # If the current directory resides on the local node pass the zfgcwd
+ # request to the local kernel, else pass it to the kernel on the remote
+ # (default) node. Leave the CWD in p_sbuf.
+
+ if (n_default == NULL || n_default == n_local) {
+err_ call zfgcwd (p_sbuf, SZ_SBUF, nchars)
+ call strupk (p_sbuf, p_sbuf, SZ_SBUF)
+ p_arg[2] = 1
+
+ } else {
+ # If the current directory is on a remote node then there must be
+ # a connected kernel server attached to that node.
+
+ server = n_default
+
+ if (ki_sendrcv (server, KI_ZFGCWD, 0) == ERR) {
+ n_default = n_local
+ goto err_
+ }
+ }
+
+ # Return node // directory.
+
+ op = gstrcpy (n_defaultnode, outstr, maxch) + 1
+ if (op > 1) {
+ outstr[op] = FNNODE_CHAR
+ op = op + 1
+ }
+
+ nchars = op + gstrcpy (p_sbuf[p_arg[2]], outstr[op], maxch-op+1)
+ call strpak (outstr, outstr, maxch)
+end
diff --git a/sys/ki/kfinfo.x b/sys/ki/kfinfo.x
new file mode 100644
index 00000000..cfc0353d
--- /dev/null
+++ b/sys/ki/kfinfo.x
@@ -0,0 +1,42 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <finfo.h>
+include "ki.h"
+
+# KFINFO -- Get directory info on a file.
+
+procedure kfinfo (osfn, fi, status)
+
+char osfn[ARB] # packed os filename
+long fi[ARB] # receives finfo structure
+int status # answer; ok or err
+
+int server, i
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfinfo (p_sbuf, fi, status)
+
+ } else {
+ if (ki_sendrcv (server, KI_ZFINFO, 0) == ERR)
+ status = ERR
+ else {
+ status = p_arg[1]
+
+ # The finfo structure is returned in ARG except for the
+ # owner string, which is returned in sbuf. Note that we
+ # are passing longs in ints hence precision could conceivably
+ # be lost (most unlikely).
+
+ do i = 1, FI_NINTFIELDS
+ fi[i] = p_arg[i+1]
+ call strpak (p_sbuf, FI_OWNER(fi), FI_SZOWNER)
+ }
+ }
+end
diff --git a/sys/ki/kfiobf.x b/sys/ki/kfiobf.x
new file mode 100644
index 00000000..50d7f500
--- /dev/null
+++ b/sys/ki/kfiobf.x
@@ -0,0 +1,110 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KFIOBF -- Binary file driver.
+
+procedure kopnbf (osfn, mode, chan)
+
+char osfn[ARB]
+int mode, chan
+
+int server
+int ki_connect(), ki_getchan()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopnbf (p_sbuf, mode, chan)
+ if (chan != ERR)
+ chan = ki_getchan (server, chan)
+ } else
+ call kb_zopn (KI_ZFIOBF, osfn, mode, chan)
+end
+
+
+procedure kclsbf (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ if (k_node[chan] == NULL) {
+ call zclsbf (k_oschan[chan], status)
+ call ki_freechan (chan)
+ } else
+ call kb_zcls (KI_ZFIOBF, chan, status)
+end
+
+
+procedure kardbf (chan, buf, max_bytes, offset)
+
+int chan
+char buf[ARB]
+int max_bytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zardbf (k_oschan[chan], buf, max_bytes, offset)
+ else
+ call kb_zard (KI_ZFIOBF, chan, buf, max_bytes, offset)
+end
+
+
+procedure kawrbf (chan, buf, nbytes, offset)
+
+int chan
+char buf[ARB]
+int nbytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawrbf (k_oschan[chan], buf, nbytes, offset)
+ else
+ call kb_zawr (KI_ZFIOBF, chan, buf, nbytes, offset)
+end
+
+
+procedure kawtbf (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawtbf (k_oschan[chan], status)
+ else
+ call kb_zawt (KI_ZFIOBF, chan, status)
+end
+
+
+procedure ksttbf (chan, what, lvalue)
+
+int chan
+int what
+long lvalue
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsttbf (k_oschan[chan], what, lvalue)
+ else
+ call kb_zstt (KI_ZFIOBF, chan, what, lvalue)
+end
diff --git a/sys/ki/kfiogd.x b/sys/ki/kfiogd.x
new file mode 100644
index 00000000..bde39350
--- /dev/null
+++ b/sys/ki/kfiogd.x
@@ -0,0 +1,110 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KFIOGD -- Binary graphics device file driver.
+
+procedure kopngd (osfn, mode, chan)
+
+char osfn[ARB]
+int mode, chan
+
+int server
+int ki_connect(), ki_getchan()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopngd (p_sbuf, mode, chan)
+ if (chan != ERR)
+ chan = ki_getchan (server, chan)
+ } else
+ call kb_zopn (KI_ZFIOGD, osfn, mode, chan)
+end
+
+
+procedure kclsgd (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ if (k_node[chan] == NULL) {
+ call zclsgd (k_oschan[chan], status)
+ call ki_freechan (chan)
+ } else
+ call kb_zcls (KI_ZFIOGD, chan, status)
+end
+
+
+procedure kardgd (chan, buf, max_bytes, offset)
+
+int chan
+char buf[ARB]
+int max_bytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zardgd (k_oschan[chan], buf, max_bytes, offset)
+ else
+ call kb_zard (KI_ZFIOGD, chan, buf, max_bytes, offset)
+end
+
+
+procedure kawrgd (chan, buf, nbytes, offset)
+
+int chan
+char buf[ARB]
+int nbytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawrgd (k_oschan[chan], buf, nbytes, offset)
+ else
+ call kb_zawr (KI_ZFIOGD, chan, buf, nbytes, offset)
+end
+
+
+procedure kawtgd (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawtgd (k_oschan[chan], status)
+ else
+ call kb_zawt (KI_ZFIOGD, chan, status)
+end
+
+
+procedure ksttgd (chan, what, lvalue)
+
+int chan
+int what
+long lvalue
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsttgd (k_oschan[chan], what, lvalue)
+ else
+ call kb_zstt (KI_ZFIOGD, chan, what, lvalue)
+end
diff --git a/sys/ki/kfiolp.x b/sys/ki/kfiolp.x
new file mode 100644
index 00000000..7e642b00
--- /dev/null
+++ b/sys/ki/kfiolp.x
@@ -0,0 +1,110 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KFIOLP -- Line printer driver.
+
+procedure kopnlp (osfn, mode, chan)
+
+char osfn[ARB]
+int mode, chan
+
+int server
+int ki_connect(), ki_getchan()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopnlp (p_sbuf, mode, chan)
+ if (chan != ERR)
+ chan = ki_getchan (server, chan)
+ } else
+ call kb_zopn (KI_ZFIOLP, osfn, mode, chan)
+end
+
+
+procedure kclslp (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ if (k_node[chan] == NULL) {
+ call zclslp (k_oschan[chan], status)
+ call ki_freechan (chan)
+ } else
+ call kb_zcls (KI_ZFIOLP, chan, status)
+end
+
+
+procedure kardlp (chan, buf, max_bytes, offset)
+
+int chan
+char buf[ARB]
+int max_bytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zardlp (k_oschan[chan], buf, max_bytes, offset)
+ else
+ call kb_zard (KI_ZFIOLP, chan, buf, max_bytes, offset)
+end
+
+
+procedure kawrlp (chan, buf, nbytes, offset)
+
+int chan
+char buf[ARB]
+int nbytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawrlp (k_oschan[chan], buf, nbytes, offset)
+ else
+ call kb_zawr (KI_ZFIOLP, chan, buf, nbytes, offset)
+end
+
+
+procedure kawtlp (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawtlp (k_oschan[chan], status)
+ else
+ call kb_zawt (KI_ZFIOLP, chan, status)
+end
+
+
+procedure ksttlp (chan, what, lvalue)
+
+int chan
+int what
+long lvalue
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsttlp (k_oschan[chan], what, lvalue)
+ else
+ call kb_zstt (KI_ZFIOLP, chan, what, lvalue)
+end
diff --git a/sys/ki/kfiopl.x b/sys/ki/kfiopl.x
new file mode 100644
index 00000000..346101cc
--- /dev/null
+++ b/sys/ki/kfiopl.x
@@ -0,0 +1,110 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include <mach.h>
+include "ki.h"
+
+# KFIOPL -- Plotter driver (NSPP metacode translator).
+
+procedure kopnpl (osfn, mode, chan)
+
+char osfn[ARB]
+int mode, chan
+
+int server
+int ki_connect(), ki_getchan()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopnpl (p_sbuf, mode, chan)
+ if (chan != ERR)
+ chan = ki_getchan (server, chan)
+ } else
+ call kb_zopn (KI_ZFIOPL, osfn, mode, chan)
+end
+
+
+procedure kclspl (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ if (k_node[chan] == NULL) {
+ call zclspl (k_oschan[chan], status)
+ call ki_freechan (chan)
+ } else
+ call kb_zcls (KI_ZFIOPL, chan, status)
+end
+
+
+procedure kardpl (chan, buf, max_bytes, offset)
+
+int chan
+char buf[ARB]
+int max_bytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zardpl (k_oschan[chan], buf, max_bytes, offset)
+ else
+ call kb_zard (KI_ZFIOPL, chan, buf, max_bytes, offset)
+end
+
+
+procedure kawrpl (chan, buf, nbytes, offset)
+
+int chan
+char buf[ARB]
+int nbytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawrpl (k_oschan[chan], buf, nbytes, offset)
+ else
+ call kb_zawr (KI_ZFIOPL, chan, buf, nbytes, offset)
+end
+
+
+procedure kawtpl (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawtpl (k_oschan[chan], status)
+ else
+ call kb_zawt (KI_ZFIOPL, chan, status)
+end
+
+
+procedure ksttpl (chan, what, lvalue)
+
+int chan
+int what
+long lvalue
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsttpl (k_oschan[chan], what, lvalue)
+ else
+ call kb_zstt (KI_ZFIOPL, chan, what, lvalue)
+end
diff --git a/sys/ki/kfiopr.x b/sys/ki/kfiopr.x
new file mode 100644
index 00000000..2abae18e
--- /dev/null
+++ b/sys/ki/kfiopr.x
@@ -0,0 +1,106 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KFIOPR -- IPC driver. This driver has no open and close entry points since
+# these functions are provided by the ZOPCPR and ZCLCPR procedures, which also
+# spawn the subprocess.
+
+# procedure kopnpr (osfn, mode, chan)
+#
+# char osfn[ARB]
+# int mode, chan
+#
+# int server
+# int ki_connect(), ki_getchan()
+# include "kii.com"
+#
+# begin
+# server = ki_connect (osfn)
+#
+# if (server == NULL) {
+# call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+# call zopnpr (p_sbuf, mode, chan)
+# if (chan != ERR)
+# chan = ki_getchan (server, chan)
+# } else
+# call kb_zopn (KI_ZFIOPR, osfn, mode, chan)
+# end
+#
+#
+# procedure kclspr (chan, status)
+#
+# int chan
+# int status
+# include "kichan.com"
+#
+# begin
+# if (k_node[chan] == NULL) {
+# call zclspr (k_oschan[chan], status)
+# k_oschan[chan] = NULL
+# } else
+# call kb_zcls (KI_ZFIOPR, chan, status)
+# end
+
+
+procedure kardpr (chan, buf, max_bytes, offset)
+
+int chan
+char buf[ARB]
+int max_bytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zardpr (k_oschan[chan], buf, max_bytes, offset)
+ else
+ call kb_zard (KI_ZFIOPR, chan, buf, max_bytes, offset)
+end
+
+
+procedure kawrpr (chan, buf, nbytes, offset)
+
+int chan
+char buf[ARB]
+int nbytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawrpr (k_oschan[chan], buf, nbytes, offset)
+ else
+ call kb_zawr (KI_ZFIOPR, chan, buf, nbytes, offset)
+end
+
+
+procedure kawtpr (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawtpr (k_oschan[chan], status)
+ else
+ call kb_zawt (KI_ZFIOPR, chan, status)
+end
+
+
+procedure ksttpr (chan, what, lvalue)
+
+int chan
+int what
+long lvalue
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsttpr (k_oschan[chan], what, lvalue)
+ else
+ call kb_zstt (KI_ZFIOPR, chan, what, lvalue)
+end
diff --git a/sys/ki/kfiosf.x b/sys/ki/kfiosf.x
new file mode 100644
index 00000000..c14cc13c
--- /dev/null
+++ b/sys/ki/kfiosf.x
@@ -0,0 +1,112 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KFIOSF -- Static file driver. Since the static file driver may permit
+# portions of a data file to be mapped into virtual memory, use the binary
+# file driver if the file resides on a remote node.
+
+procedure kopnsf (osfn, mode, chan)
+
+char osfn[ARB]
+int mode, chan
+
+int server
+int ki_connect(), ki_getchan()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopnsf (p_sbuf, mode, chan)
+ if (chan != ERR)
+ chan = ki_getchan (server, chan)
+ } else
+ call kb_zopn (KI_ZFIOBF, osfn, mode, chan)
+end
+
+
+procedure kclssf (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ if (k_node[chan] == NULL) {
+ call zclssf (k_oschan[chan], status)
+ call ki_freechan (chan)
+ } else
+ call kb_zcls (KI_ZFIOBF, chan, status)
+end
+
+
+procedure kardsf (chan, buf, max_bytes, offset)
+
+int chan
+char buf[ARB]
+int max_bytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zardsf (k_oschan[chan], buf, max_bytes, offset)
+ else
+ call kb_zard (KI_ZFIOBF, chan, buf, max_bytes, offset)
+end
+
+
+procedure kawrsf (chan, buf, nbytes, offset)
+
+int chan
+char buf[ARB]
+int nbytes
+long offset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawrsf (k_oschan[chan], buf, nbytes, offset)
+ else
+ call kb_zawr (KI_ZFIOBF, chan, buf, nbytes, offset)
+end
+
+
+procedure kawtsf (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zawtsf (k_oschan[chan], status)
+ else
+ call kb_zawt (KI_ZFIOBF, chan, status)
+end
+
+
+procedure ksttsf (chan, what, lvalue)
+
+int chan
+int what
+long lvalue
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsttsf (k_oschan[chan], what, lvalue)
+ else
+ call kb_zstt (KI_ZFIOBF, chan, what, lvalue)
+end
diff --git a/sys/ki/kfiotx.x b/sys/ki/kfiotx.x
new file mode 100644
index 00000000..b329c674
--- /dev/null
+++ b/sys/ki/kfiotx.x
@@ -0,0 +1,157 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <fio.h>
+include "ki.h"
+
+# KFIOTX -- Text file driver.
+
+procedure kopntx (osfn, mode, chan)
+
+char osfn[ARB] # packed os filename
+int mode # access mode
+int chan # receives channel code
+
+int server
+int ki_connect(), ki_getchan()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopntx (p_sbuf, mode, chan)
+ if (chan != ERR)
+ chan = ki_getchan (server, chan)
+ } else
+ call kt_zopn (KI_ZFIOTX, osfn, mode, chan)
+end
+
+
+procedure kclstx (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ if (k_node[chan] == NULL) {
+ call zclstx (k_oschan[chan], status)
+ call ki_freechan (chan)
+ } else
+ call kt_zcls (KI_ZFIOTX, chan, status)
+end
+
+
+procedure kgettx (chan, text, maxch, status)
+
+int chan
+char text[maxch]
+int maxch, status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zgettx (k_oschan[chan], text, maxch, status)
+ else
+ call kt_zget (KI_ZFIOTX, chan, text, maxch, status)
+end
+
+
+procedure kputtx (chan, text, nchars, status)
+
+int chan
+char text[nchars]
+int nchars, status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zputtx (k_oschan[chan], text, nchars, status)
+ else
+ call kt_zput (KI_ZFIOTX, chan, text, nchars, status)
+end
+
+
+procedure kflstx (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zflstx (k_oschan[chan], status)
+ else
+ call kt_zfls (KI_ZFIOTX, chan, status)
+end
+
+
+procedure ksektx (chan, loffset, status)
+
+int chan
+long loffset
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsektx (k_oschan[chan], loffset, status)
+ else
+ call kt_zsek (KI_ZFIOTX, chan, loffset, status)
+end
+
+
+procedure knottx (chan, loffset)
+
+int chan
+long loffset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call znottx (k_oschan[chan], loffset)
+ else
+ call kt_znot (KI_ZFIOTX, chan, loffset)
+end
+
+
+procedure kstttx (chan, what, lvalue)
+
+int chan
+int what
+long lvalue
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zstttx (k_oschan[chan], what, lvalue)
+ else {
+ # Querying the text file status parameters is slow over the net,
+ # and they are essentially constants anyhow, so just return the
+ # expected values.
+ #
+ # call kt_zstt (KI_ZFIOTX, chan, what, lvalue)
+
+ switch (what) {
+ case FSTT_BLKSIZE:
+ lvalue = 1
+ case FSTT_FILSIZE:
+ lvalue = 1
+ case FSTT_OPTBUFSIZE:
+ lvalue = SZ_LINE
+ case FSTT_MAXBUFSIZE:
+ lvalue = 0
+ default:
+ lvalue = ERR
+ }
+ }
+end
diff --git a/sys/ki/kfioty.x b/sys/ki/kfioty.x
new file mode 100644
index 00000000..4726f5c3
--- /dev/null
+++ b/sys/ki/kfioty.x
@@ -0,0 +1,138 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KFIOTY -- Terminal driver.
+
+procedure kopnty (osfn, mode, chan)
+
+char osfn[ARB] # packed os filename
+int mode # access mode
+int chan # receives channel code
+
+int server
+int ki_connect(), ki_getchan()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopnty (p_sbuf, mode, chan)
+ if (chan != ERR)
+ chan = ki_getchan (server, chan)
+ } else
+ call kt_zopn (KI_ZFIOTY, osfn, mode, chan)
+end
+
+
+procedure kclsty (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ if (k_node[chan] == NULL) {
+ call zclsty (k_oschan[chan], status)
+ call ki_freechan (chan)
+ } else
+ call kt_zcls (KI_ZFIOTY, chan, status)
+end
+
+
+procedure kgetty (chan, text, maxch, status)
+
+int chan
+char text[maxch]
+int maxch, status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zgetty (k_oschan[chan], text, maxch, status)
+ else
+ call kt_zget (KI_ZFIOTY, chan, text, maxch, status)
+end
+
+
+procedure kputty (chan, text, nchars, status)
+
+int chan
+char text[nchars]
+int nchars, status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zputty (k_oschan[chan], text, nchars, status)
+ else
+ call kt_zput (KI_ZFIOTY, chan, text, nchars, status)
+end
+
+
+procedure kflsty (chan, status)
+
+int chan
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zflsty (k_oschan[chan], status)
+ else
+ call kt_zfls (KI_ZFIOTY, chan, status)
+end
+
+
+procedure ksekty (chan, loffset, status)
+
+int chan
+long loffset
+int status
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsekty (k_oschan[chan], loffset, status)
+ else
+ call kt_zsek (KI_ZFIOTY, chan, loffset, status)
+end
+
+
+procedure knotty (chan, loffset)
+
+int chan
+long loffset
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call znotty (k_oschan[chan], loffset)
+ else
+ call kt_znot (KI_ZFIOTY, chan, loffset)
+end
+
+
+procedure ksttty (chan, what, lvalue)
+
+int chan
+int what
+long lvalue
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zsttty (k_oschan[chan], what, lvalue)
+ else
+ call kt_zstt (KI_ZFIOTY, chan, what, lvalue)
+end
diff --git a/sys/ki/kfmkcp.x b/sys/ki/kfmkcp.x
new file mode 100644
index 00000000..675aa1b3
--- /dev/null
+++ b/sys/ki/kfmkcp.x
@@ -0,0 +1,136 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+
+# KFMKCP -- Make a null length copy of a file. The new file inherits the
+# attributes of the existing file. This works provided both files are on
+# the same node; since the kernel routine is atomic and must access both
+# files, and the attributes are OS dependent, there is no way to inherit
+# the attributes if the files reside on different nodes.
+
+procedure kfmkcp (old_osfn, new_osfn, status)
+
+char old_osfn[ARB] # packed os filename of existing file
+char new_osfn[ARB] # packed os filename of new file
+int status # answer; ok or err
+
+pointer sp, fname
+int server1, server2, chan, junk, old, new
+int ki_connect(), ki_sendrcv(), strlen()
+include "kii.com"
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ server2 = ki_connect (new_osfn)
+ call strcpy (p_sbuf[p_arg[1]], Memc[fname], SZ_FNAME)
+ server1 = ki_connect (old_osfn)
+ old = p_arg[1]
+
+ if (server1 == NULL && server2 == NULL) {
+ # Both files reside on the local node.
+
+ call strpak (p_sbuf[old], p_sbuf[old], SZ_SBUF)
+ call strpak (Memc[fname], Memc[fname], SZ_FNAME)
+ call zfmkcp (p_sbuf[old], Memc[fname], status)
+
+ } else if (server1 == server2) {
+ # Both files reside on the same remote node.
+
+ new = old + strlen(p_sbuf[old])+1 + 1
+ if (new + strlen(Memc[fname])+1 > SZ_SBUF)
+ status = ERR
+ else {
+ call strcpy (Memc[fname], p_sbuf[new], SZ_SBUF-new+1)
+
+ p_arg[2] = new
+ p_sbuflen = SZ_SBUF
+
+ if (ki_sendrcv (server1, KI_ZFMKCP, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+
+ } else if (server1 != NULL && server2 != NULL) {
+ # Both files are remote. Cannot transfer all attributes;
+ # the best we can do is create either a text or binary file.
+
+ call kfacss (old_osfn, 0, TEXT_FILE, status)
+ call strpak (Memc[fname], Memc[fname], SZ_FNAME)
+
+ if (status == YES) {
+ # Create a text file.
+ call kopntx (new_osfn, NEW_FILE, chan)
+ if (chan != ERR) {
+ call kclstx (chan, junk)
+ status = chan
+ } else
+ status = ERR
+ } else {
+ # Create a binary file.
+ call kopnbf (new_osfn, NEW_FILE, chan)
+ if (chan != ERR) {
+ call kclsbf (chan, junk)
+ status = chan
+ } else
+ status = ERR
+ }
+
+ } else if (server1 != NULL) {
+ # The existing file is remote. Cannot transfer all attributes;
+ # the best we can do is create either a text or binary file.
+ # Call ZFACSS to determine the file type of the existing file
+ # and create a null length text or binary file.
+
+ call kfacss (old_osfn, 0, TEXT_FILE, status)
+ call strpak (Memc[fname], Memc[fname], SZ_FNAME)
+
+ if (status == YES) {
+ # Create a text file.
+ call zopntx (Memc[fname], NEW_FILE, chan)
+ if (chan != ERR) {
+ call zclstx (chan, junk)
+ status = chan
+ } else
+ status = ERR
+ } else {
+ # Create a binary file.
+ call zopnbf (Memc[fname], NEW_FILE, chan)
+ if (chan != ERR) {
+ call zclsbf (chan, junk)
+ status = chan
+ } else
+ status = ERR
+ }
+
+ } else {
+ # The new file is remote.
+
+ call strpak (p_sbuf[old], p_sbuf[old], SZ_SBUF)
+ call zfacss (p_sbuf[old], 0, TEXT_FILE, status)
+
+ if (status == YES) {
+ # Create a text file.
+ call kopntx (new_osfn, NEW_FILE, chan)
+ if (chan != ERR) {
+ call kclstx (chan, junk)
+ status = chan
+ } else
+ status = ERR
+ } else {
+ # Create a binary file.
+ call kopnbf (new_osfn, NEW_FILE, chan)
+ if (chan != ERR) {
+ call kclsbf (chan, junk)
+ status = chan
+ } else
+ status = ERR
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/ki/kfmkdr.x b/sys/ki/kfmkdr.x
new file mode 100644
index 00000000..8e32ac50
--- /dev/null
+++ b/sys/ki/kfmkdr.x
@@ -0,0 +1,30 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KFMKDR -- Make a new directory.
+
+procedure kfmkdr (osfn, status)
+
+char osfn[ARB] # packed os filename of directory
+int status # ok or err
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfmkdr (p_sbuf, status)
+
+ } else {
+ if (ki_sendrcv (server, KI_ZFMKDR, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kfpath.x b/sys/ki/kfpath.x
new file mode 100644
index 00000000..6522e5f2
--- /dev/null
+++ b/sys/ki/kfpath.x
@@ -0,0 +1,56 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "ki.h"
+
+# KFPATH -- Convert a VFN into a net pathname. The VFN may contain a node
+# pathname and the final pathname will always include the node name.
+
+procedure kfpath (vfn, osfn, maxch, nchars)
+
+char vfn[ARB] # virtual filename
+char osfn[maxch] # receives pathname
+int maxch # max chars out
+int nchars # receives length of osfn string
+
+int delim, op, nodeflag, junk
+int ki_gnode(), gstrcpy(), ki_gethosts()
+include "kinode.com"
+
+begin
+ # Read the host name table if it has not been read yet.
+ if (n_nnodes == 0)
+ junk = ki_gethosts()
+
+ # If no VFN is given return the current working directory.
+ if (vfn[1] == EOS) {
+ call kfgcwd (osfn, maxch, nchars)
+ call strupk (osfn, osfn, maxch)
+ return
+ }
+
+ # Determine what node the given VFN resides on.
+ nodeflag = ki_gnode (vfn, osfn, delim)
+
+ # Append the node delimiter to the node name if there is a node name.
+ for (op=1; osfn[op] != EOS; op=op+1)
+ ;
+ if (op > 1) {
+ osfn[op] = FNNODE_CHAR
+ op = op + 1
+ }
+
+ if (nodeflag == LOCAL) {
+ # File is on the local node. Return the mapped pathname with
+ # the node name of the local node prepended.
+
+ call zfpath (vfn[delim+1], osfn[op], maxch-op+1, nchars)
+ nchars = nchars + op - 1
+
+ } else {
+ # File is on a remote node. Do not map the filename; leave that
+ # to the kernel when the file is referenced at runtime.
+
+ nchars = gstrcpy (vfn[delim+1], osfn[op], maxch-op+1) + op - 1
+ }
+end
diff --git a/sys/ki/kfprot.x b/sys/ki/kfprot.x
new file mode 100644
index 00000000..d2338d8f
--- /dev/null
+++ b/sys/ki/kfprot.x
@@ -0,0 +1,33 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KFPROT -- Set or query file protection.
+
+procedure kfprot (osfn, protflag, status)
+
+char osfn[ARB] # packed os filename
+int protflag # set/query flag
+int status # answer; yes or no
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfprot (p_sbuf, protflag, status)
+
+ } else {
+ p_arg[2] = protflag
+
+ if (ki_sendrcv (server, KI_ZFPROT, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kfrmdr.x b/sys/ki/kfrmdr.x
new file mode 100644
index 00000000..e468a86f
--- /dev/null
+++ b/sys/ki/kfrmdr.x
@@ -0,0 +1,30 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KFRMDR -- Remove a directory.
+
+procedure kfrmdr (osfn, status)
+
+char osfn[ARB] # packed os filename of directory
+int status # ok or err
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfrmdr (p_sbuf, status)
+
+ } else {
+ if (ki_sendrcv (server, KI_ZFRMDR, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kfrnam.x b/sys/ki/kfrnam.x
new file mode 100644
index 00000000..d2600aaa
--- /dev/null
+++ b/sys/ki/kfrnam.x
@@ -0,0 +1,61 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+
+# KFRNAM -- Rename a file. Both filenames must refer to the same node.
+
+procedure kfrnam (old_osfn, new_osfn, status)
+
+char old_osfn[ARB] #I packed old os filename
+char new_osfn[ARB] #I packed new os filename
+int status #O answer; ok or err
+
+pointer sp, fname
+int server1, server2, old, new
+int ki_connect(), ki_sendrcv(), strlen()
+include "kii.com"
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ server2 = ki_connect (new_osfn)
+ call strcpy (p_sbuf[p_arg[1]], Memc[fname], SZ_FNAME)
+ server1 = ki_connect (old_osfn)
+ old = p_arg[1]
+
+ if (server1 == NULL && server2 == NULL) {
+ # Both files reside on the local node.
+
+ call strpak (p_sbuf[old], p_sbuf[old], SZ_SBUF)
+ call strpak (Memc[fname], Memc[fname], SZ_FNAME)
+ call zfrnam (p_sbuf[old], Memc[fname], status)
+
+ } else if (server1 == server2) {
+ # Both files reside on the same remote node. Pack the two
+ # filenames into p_sbuf and send the request.
+
+ new = old + strlen(p_sbuf[old])+1 + 1
+ if (new + strlen(Memc[fname])+1 > SZ_SBUF)
+ status = ERR
+ else {
+ call strcpy (Memc[fname], p_sbuf[new], SZ_SBUF-new+1)
+
+ p_arg[2] = new
+ p_sbuflen = SZ_SBUF
+
+ if (ki_sendrcv (server1, KI_ZFRNAM, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+
+ } else {
+ # One file resides on a remote node.
+ status = ERR
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/ki/kfsubd.x b/sys/ki/kfsubd.x
new file mode 100644
index 00000000..93f2d655
--- /dev/null
+++ b/sys/ki/kfsubd.x
@@ -0,0 +1,52 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "ki.h"
+
+# KFSUBD -- Compute the net pathname of a subdirectory given the net pathname
+# of the parent directory and the name of the subdirectory (the logical
+# subdirectory names . and .. are supported). If the subdirectory resides on
+# the local node we call the local kernel to compute the new directory pathname.
+# If the directory resides on a remote node we merely append to the virtual
+# pathname, leaving resolution of the final pathname to the remote kernel when
+# the file is referenced at runtime.
+
+procedure kfsubd (osdir, maxch, subdir, nchars)
+
+char osdir[maxch] #RW net pathname of directory
+int maxch #RO max chars out in osdir string
+char subdir[ARB] #RO receives pathname
+int nchars #WO receives length of osfn string
+
+int delim, op
+char alias[SZ_ALIAS]
+int ki_gnode(), gstrcat()
+
+begin
+ if (ki_gnode (osdir, alias, delim) == LOCAL) {
+ # Directory is on the local node.
+
+ if (osdir[delim+1] == EOS) {
+ call zfgcwd (osdir[delim+1], maxch - delim, nchars)
+ if (nchars == ERR)
+ return
+ call strupk (osdir[delim+1], osdir[delim+1], maxch-delim)
+ }
+ call zfsubd (osdir[delim+1], maxch - delim, subdir, nchars)
+ if (nchars != ERR)
+ nchars = nchars + delim
+
+ } else {
+ # File is on a remote node. Do not map the filename; leave that
+ # to the kernel when the file is referenced at runtime. The OSDIR
+ # string is assumed to be a concatenatable VFN (with node prefix).
+
+ op = gstrcat (subdir, osdir, maxch) + 1
+ if (op > 1 && osdir[op-1] != '/') {
+ osdir[op] = '/'
+ op = op + 1
+ osdir[op] = EOS
+ }
+
+ nchars = op - 1
+ }
+end
diff --git a/sys/ki/kfutim.x b/sys/ki/kfutim.x
new file mode 100644
index 00000000..a4b81156
--- /dev/null
+++ b/sys/ki/kfutim.x
@@ -0,0 +1,38 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KFUTIM -- Set the file access/modify times of a file. Time arguments are
+# assumed to be in units of seconds from midnight on Jan 1, 1980, LST.
+#
+# NOTE: Since the atime/mtime values are long but the p_arg[] is just int
+# this code may need to be revised if the sizes of long/int change.
+
+procedure kfutim (osfn, atime, mtime, status)
+
+char osfn[ARB] # packed os filename
+long atime, mtime # access and modify times
+int status # answer; ok or err
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zfutim (p_sbuf, atime, mtime, status)
+
+ } else {
+ p_arg[2] = atime
+ p_arg[3] = mtime
+
+ if (ki_sendrcv (server, KI_ZFUTIM, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kfxdir.x b/sys/ki/kfxdir.x
new file mode 100644
index 00000000..3a4209ba
--- /dev/null
+++ b/sys/ki/kfxdir.x
@@ -0,0 +1,76 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "ki.h"
+
+# KFXDIR -- Extract the OSDIR prefix (if any) from a filename. If the VFN
+# has a node prefix and the node named is not the local node then the entire
+# filename is treated as an OSDIR name. We are called during filename mapping
+# to determine if a VFN is an OSFN; returning nchars > 0 when there is a node
+# name prefix causes filename mapping to be deferred until the filename is
+# passed to the kernel server on the remote node.
+#
+# NOTE -- The "nchars" returned is the length of the osdir prefix portion of
+# the VFN string, NOT the length of the returned string. ZFXDIR is used to
+# test if a VFN has an OSDIR prefix and if so, to determine the string offset
+# of the root field.
+
+procedure kfxdir (vfn, osdir, maxch, nchars)
+
+char vfn[ARB] # virtual filename
+char osdir[maxch] # receives os directory prefix
+int maxch # max chars out
+int nchars # receives length of osdir prefix in VFN string
+
+int delim, op
+int ki_gnode(), gstrcpy(), ki_gethosts()
+include "kinode.com"
+
+begin
+ repeat {
+ if (ki_gnode (vfn, osdir, delim) == LOCAL) {
+ # File is on the local node. Must strip the node prefix,
+ # if any, before calling zfxdir, but keep the node prefix
+ # in the output pathname else the next operator will assume
+ # the default node.
+
+ for (op=1; osdir[op] != EOS; op=op+1)
+ ;
+ if (op > 1) {
+ osdir[op] = FNNODE_CHAR
+ op = op + 1
+ }
+
+ call zfxdir (vfn[delim+1], osdir[op], maxch-op+1, nchars)
+ if (nchars == 0)
+ osdir[1] = EOS
+ else
+ nchars = nchars + delim
+
+ break
+
+ } else {
+ # Verify that the host name table has been read and if not,
+ # read it and try again.
+
+ if (n_nnodes == 0)
+ if (ki_gethosts() != ERR)
+ next
+
+ # File is on a remote node. Concatenate node name and filename
+ # and return the entire string as the "osdir" string, disabling
+ # filename mapping on the local node.
+
+ for (op=1; osdir[op] != EOS; op=op+1)
+ ;
+
+ if (op > 1) {
+ osdir[op] = FNNODE_CHAR
+ op = op + 1
+ }
+
+ nchars = gstrcpy (vfn[delim+1], osdir[op], maxch-op+1) + delim
+ break
+ }
+ }
+end
diff --git a/sys/ki/kgfdir.x b/sys/ki/kgfdir.x
new file mode 100644
index 00000000..01926195
--- /dev/null
+++ b/sys/ki/kgfdir.x
@@ -0,0 +1,124 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KGFDIR -- Get the next filename from a directory file. Rather than make a
+# call over the net to read each filename, which would be very slow, we read
+# filenames in large batches and return filenames out of our internal buffer.
+
+procedure kgfdir (chan, osfn, maxch, status)
+
+int chan # channel descriptor
+char osfn[maxch] # receives packed OS filename
+int maxch # maxchars out
+int status # answer; ok or err
+
+pointer dp, bp, ip, op
+pointer sp, vfn, root, extn
+int server, nchars, len_root, len_extn
+int ki_sendrcv(), gstrcpy()
+include "kichan.com"
+include "kii.com"
+define quit_ 91
+
+begin
+ server = k_node[chan]
+
+ if (server == NULL) {
+ call zgfdir (k_oschan[chan], osfn, maxch, status)
+
+ } else {
+ call smark (sp)
+ call salloc (vfn, SZ_PATHNAME, TY_CHAR)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+ call salloc (extn, SZ_FNAME, TY_CHAR)
+
+ dp = k_bufp[chan]
+ bp = D_DATA(dp)
+
+ if (D_IP(dp) >= D_ITOP(dp)) {
+ # Refill buffer.
+
+ # If the last block of data was returned with the EOF flag
+ # set then the directory has been exhausted.
+
+ if (D_EOFSEEN(dp) == YES) {
+ status = EOF
+ goto quit_
+ }
+
+ p_arg[1] = k_oschan[chan]
+ p_arg[2] = SZ_DIRDATA
+ p_sbuflen = 0
+
+ if (ki_sendrcv (server, KI_ZGFDIR, 0) == ERR) {
+ status = ERR
+ goto quit_
+ } else if (p_arg[1] == ERR) {
+ status = ERR
+ goto quit_
+ } else if (p_arg[1] <= 0) {
+ status = EOF
+ goto quit_
+ }
+
+ nchars = p_arg[1]
+ if (nchars <= SZ_SBUF) {
+ call amovc (p_sbuf, Memc[bp], nchars)
+ p_sbuflen = nchars
+ } else {
+ call ks_aread (server, Memc[bp], nchars)
+ call ks_await (server, status)
+
+ if (status != nchars) {
+ status = ERR
+ goto quit_
+ } else
+ call chrupk (Memc[bp], 1, Memc[bp], 1, nchars)
+ }
+
+ D_IP(dp) = bp
+ D_ITOP(dp) = bp + nchars
+ D_EOFSEEN(dp) = p_arg[2]
+ }
+
+ # Return the next filename from the buffer.
+
+ for (ip=D_IP(dp); ip < D_ITOP(dp) && Memc[ip] != '\n'; ip=ip+1)
+ ;
+ Memc[ip] = EOS
+
+ if (ip > D_IP(dp)) {
+ # A kernel server always returns unmapped (IRAF) filenames since
+ # the unmapping must be performed on the host where the files
+ # are. We must map these into local host filenames since that
+ # is what the kernel interface is supposed to return.
+
+ call vfn_encode (Memc, D_IP(dp),
+ Memc[root], len_root, Memc[extn], len_extn)
+ if (len_extn > 0)
+ call vfn_map_extension (Memc[extn], Memc[extn], SZ_FNAME)
+
+ op = vfn + gstrcpy (Memc[root], Memc[vfn], SZ_PATHNAME)
+ if (len_extn > 0) {
+ Memc[op] = '.'
+ op = op + 1
+ op = op + gstrcpy (Memc[extn], Memc[op], ARB)
+ }
+
+ # Return a packed (local) host filename.
+ call strpak (Memc[vfn], osfn, maxch)
+ } else
+ op = vfn
+
+ status = op - vfn
+ if (status <= 0)
+ status = EOF
+
+ D_IP(dp) = ip + 1
+quit_
+ call sfree (sp)
+ }
+end
diff --git a/sys/ki/ki.h b/sys/ki/ki.h
new file mode 100644
index 00000000..76140c8b
--- /dev/null
+++ b/sys/ki/ki.h
@@ -0,0 +1,139 @@
+# KI.H -- IRAF Kernel Interface definitions.
+
+define MAX_NODES 512 # max nodes known to KI
+define MAX_CHANNELS LAST_FD # requires <config.h>
+define MAX_INDIRECT 20 # max indirection in a route
+define MAX_ALIAS 6 # maximum number of aliases per node
+define SZ_ALIAS 16 # size of a node name alias
+define SZ_SERVER 128 # size of a server name
+define HNT_SUBDIR "dev" # parts of host name table filename
+define HNT_FILENAME "hosts" # default host name table
+define HNT_ENVNAME "irafhnt" # user host name table
+
+define READ_IN_PROGRESS (-11) # used in binary file i/o
+define OSHIFT 128 # optype= (opcode * OSHIFT) + subcode
+define FIRST_CHAN 4 # first available kchan.
+define LOCAL 0 # node is a local node
+define REMOTE 1 # node is a remote node
+
+# Node status flags.
+define F_IOERR 01B # fatal error on kschan
+define F_REUSE 02B # node descriptor may be reused
+
+# ZFIOTX buffer descriptor.
+
+define SZ_TXBUF 16386 # size of text file buffer (should be
+ # at least (2*LEN_SEQBUF*SZ_LINE))
+define LEN_TXBDES (5+SZ_TXBUF/SZ_STRUCT)
+
+define B_CI Memi[$1] # character index into current record
+define B_RP Memi[$1+1] # pointer to current record
+define B_ITOP Memi[$1+2] # end of input buffer
+define B_OTOP Memi[$1+3] # end of output buffer
+define B_BUFTOP Memi[$1+4] # end of buffer
+define B_BUFPTR P2C(($1)+5) # first char of buffer
+
+# ZGFDIR buffer descriptor.
+
+define SZ_DIRDATA 2048 # amount of directory data to read
+define LEN_DIRBDES (5+SZ_DIRDATA/SZ_STRUCT)
+
+define D_IP Memi[$1] # input pointer into dirbuf
+define D_ITOP Memi[$1+1] # top of dirbuf
+define D_EOFSEEN Memi[$1+2] # dirbuf contains last of data
+define D_DATA P2C(($1)+5) # pointer to data area
+
+# Record descriptor structure (format of a line of text record in the input
+# buffer when reading from a remote text file).
+
+define R_RECLEN Memc[$1] # encoded record length (2 chars)
+define R_SEKOFF Memc[$1+2] # encoded seek offset (5 chars)
+define R_DATA (($1)+7) # pointer to data text
+
+define NCHARS_INT 2 # nchars to encode an int
+define NCHARS_LONG 5 # nchars to encode a long
+define R_GETNCHARS (($1)-7) # reclen to nchars
+define R_GETRECLEN (($1)+7) # nchars to reclen
+
+# KII instruction format.
+
+define LEN_INTFIELDS 16 # number of integer fields
+define FIRSTINTFIELD p_opcode # first integer field in common
+define MAX_ARGS 13 # max procedure arguments
+define SZ_SBUF 255 # size of string buffer
+define SZB_PACKET 320 # packet size, bytes
+
+# KII opcodes.
+
+define KI_ENVINIT 1
+define KI_SETROOT 2
+define KI_ZOSCMD 3
+define KI_FMAPFN 4
+
+define KI_ZFACSS 10
+define KI_ZFALOC 11
+define KI_ZFCHDR 12
+define KI_ZFDELE 13
+define KI_ZFINFO 14
+define KI_ZFGCWD 15
+define KI_ZFMKCP 16
+define KI_ZFMKDR 17
+define KI_ZFPATH 18
+define KI_ZFPROT 19
+define KI_ZFRNAM 20
+define KI_ZFRMDR 21
+define KI_ZFSUBD 22
+define KI_ZDVALL 23
+define KI_ZDVOWN 24
+define KI_ZFUTIM 25
+
+define KI_ZOPDIR 30
+define KI_ZCLDIR 31
+define KI_ZGFDIR 32
+
+define KI_ZOPDPR 35
+define KI_ZCLDPR 36
+define KI_ZOPCPR 37
+define KI_ZCLCPR 38
+define KI_ZINTPR 39
+
+# Device driver opcodes. BF must be the lowest numbered binary file driver
+# and TX must be the lowest number text file driver.
+
+define KI_ZFIOBF 40
+define KI_ZFIOLP 41
+define KI_ZFIOPL 42
+define KI_ZFIOPR 43
+define KI_ZFIOSF 44
+define KI_ZFIOGD 45
+
+define KI_ZFIOTX 50
+define KI_ZFIOTY 51
+
+define KI_ZFIOMT 55
+
+# KII subcodes.
+
+define BF_OPN 1 # binary files (BF, SF, PR, PL, etc.)
+define BF_CLS 2
+define BF_ARD 3
+define BF_AWR 4
+define BF_AWT 5
+define BF_STT 6
+
+define TX_OPN 1 # text files (TX, TY)
+define TX_CLS 2
+define TX_GET 3
+define TX_PUT 4
+define TX_FLS 5
+define TX_SEK 6
+define TX_NOT 7
+define TX_STT 8
+
+define MT_OP 1 # magtape zz-routines
+define MT_CL 2
+define MT_RD 3
+define MT_WR 4
+define MT_WT 5
+define MT_ST 6
+define MT_RW 7
diff --git a/sys/ki/kichan.com b/sys/ki/kichan.com
new file mode 100644
index 00000000..b810400f
--- /dev/null
+++ b/sys/ki/kichan.com
@@ -0,0 +1,8 @@
+# KICHAN.COM -- Channel descriptor common for the kernel interface.
+
+int k_node[MAX_CHANNELS] # kernel server node (NULL if local)
+int k_oschan[MAX_CHANNELS] # iraf kernel (host) channel or PID
+int k_status[MAX_CHANNELS] # status holding word for ZSTT
+pointer k_bufp[MAX_CHANNELS] # buffer pointer
+
+common /kichan/ k_node, k_oschan, k_status, k_bufp
diff --git a/sys/ki/kiconnect.x b/sys/ki/kiconnect.x
new file mode 100644
index 00000000..ed382096
--- /dev/null
+++ b/sys/ki/kiconnect.x
@@ -0,0 +1,115 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <chars.h>
+include "ki.h"
+
+# KI_CONNECT -- Given a resource name (e.g., a VFN, OSFN, or any string
+# which might begin with a node name prefix) extract the node name alias,
+# if any, and return the node index of the kernel server for the node.
+# NULL is returned if the resource does not reside on a remote node,
+# if the named node is not recognized, if the resource resides on the local
+# node, or if a kernel server cannot be spawned on the node.
+#
+# SIDE-EFFECTS: In all cases the unpacked name, minus the node name prefix,
+# is left in the field P_SBUF of the kschan common, i.e., in the packet to be
+# sent to the node to service the request. This stripped name should be used
+# even if the resource is local since the node prefix must not be passed to the
+# iraf kernel. If the resource resides on a remote node the P_ARG[1] field is
+# set to 1 (the index of the string in the string buffer) and the P_SBUFLEN
+# field is set to the length of the unpacked string plus 1 for the EOS.
+
+int procedure ki_connect (rname)
+
+char rname[ARB] # packed resource name, e.g., a filename
+
+pointer sp, sbuf, op
+char alias[SZ_ALIAS]
+int node, delim, junk, nlookup
+int ki_findnode(), ki_openks(), ki_gnode(), ki_gethosts()
+int strlen(), gstrcpy()
+
+include "kinode.com"
+include "kichan.com"
+include "kii.com"
+define again_ 91
+
+begin
+ # Read dev$hosts if it has not already been read.
+ if (n_nnodes == 0)
+ junk = ki_gethosts()
+
+ # Unpack rname into the string buffer, search for the node character.
+ # The call to KI_GETHOSTS will fail during process startup until the
+ # environment variable "iraf" is defined. This is harmless provided
+ # only local files are referenced during process startup. Do not
+ # move this initialization code to ki_init() or the host name table
+ # will never be read and networking will never be turned on. Return
+ # immediately if no nodechar found.
+ #
+ # NOTE: we are required to always leave the unpacked, node prefix
+ # stripped resource name in p_sbuf, whether or not the resource is
+ # on a remote node.
+
+ call strupk (rname, p_sbuf, SZ_SBUF)
+ nlookup = 0
+again_
+ if (ki_gnode (p_sbuf, alias, delim) == LOCAL) {
+ p_arg[1] = delim + 1
+ return (NULL)
+ } else
+ p_arg[1] = delim + 1
+
+ # Find node descriptor (initialized by ki_gethosts above). NULL is
+ # returned for ND if the node is not found or if the node is the
+ # local node.
+
+ node = ki_findnode (alias)
+ if (node == n_local)
+ node = NULL
+ else if (n_server[1,node] == '@') {
+ # The node entry is a route to another node. This is an entry
+ # such as "node : @foo!node". We replace the "node" prefix in
+ # rname by whatever is to the right of the @, and repeat the
+ # host lookup. In the example this would have the effect of
+ # changing the "node!object" reference to "foo!node!object" and
+ # hence routing traffic for node "node" through node "foo".
+ # This is often done when a node is not directly reachable on
+ # the local network.
+
+ call smark (sp)
+ call salloc (sbuf, SZ_SBUF, TY_CHAR)
+
+ op = sbuf + gstrcpy (n_server[2,node], Memc[sbuf], SZ_SBUF)
+ Memc[op] = '!'; op = op + 1
+ call strcpy (p_sbuf[delim+1], Memc[op], SZ_SBUF-(op-sbuf))
+ call strcpy (Memc[sbuf], p_sbuf, SZ_SBUF)
+
+ call sfree (sp)
+
+ nlookup = nlookup + 1
+ if (nlookup > MAX_INDIRECT)
+ node = NULL
+ else
+ goto again_
+ }
+
+ # Initialize the remainder of the packet descriptor variables dealing
+ # with the resource name. The node alias is left in the string buffer
+ # at offset 1, now terminated with an EOS. This is followed by RNAME
+ # minus the node name prefix. Note that RNAME may contain additional
+ # indirection; only the first node name is processed locally.
+
+ if (node != NULL) {
+ # Resource resides on a remote node. Connect the kernel server
+ # if not already connected.
+
+ p_sbuflen = strlen (p_sbuf)
+ if (n_kschan[node] == NULL)
+ if (ki_openks (node) == ERR)
+ node = NULL
+ }
+
+ return (node)
+end
diff --git a/sys/ki/kiencode.x b/sys/ki/kiencode.x
new file mode 100644
index 00000000..463579e4
--- /dev/null
+++ b/sys/ki/kiencode.x
@@ -0,0 +1,64 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# KI_ENCODE -- Encode an integer into the indicated number of chars for
+# transmission between machines via a byte stream.
+
+procedure ki_encode (data, str, nchars)
+
+long data # data value to be encoded
+char str[nchars] # output chars
+int nchars # number of chars to be encoded
+
+int i
+long v, nv
+
+begin
+ v = abs (data)
+
+ do i = 1, nchars {
+ nv = v / 128
+ str[i] = v - (nv * 128)
+ v = nv
+ }
+
+ if (data < 0)
+ if (str[1] == 0)
+ str[1] = -128
+ else
+ str[1] = -str[1]
+end
+
+
+# KI_DECODE -- Decode the long integer value encoded by ki_encode, returning
+# the long integer value as the function value.
+
+long procedure ki_decode (str, nchars)
+
+char str[ARB] # string to be decoded
+int nchars # number of chars to decode
+
+bool neg
+int pow, i
+long sum
+
+begin
+ sum = str[1]
+ neg = (sum < 0)
+ if (neg)
+ if (sum == -128)
+ sum = 0
+ else
+ sum = -sum
+
+ pow = 1
+
+ do i = 2, nchars {
+ pow = pow * 128
+ sum = sum + (str[i] * pow)
+ }
+
+ if (neg)
+ return (-sum)
+ else
+ return (sum)
+end
diff --git a/sys/ki/kienvreset.x b/sys/ki/kienvreset.x
new file mode 100644
index 00000000..5a69c519
--- /dev/null
+++ b/sys/ki/kienvreset.x
@@ -0,0 +1,69 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KI_ENVRESET -- Update the value of an environment variable on all currently
+# connected nodes.
+
+procedure ki_envreset (name, value)
+
+char name[ARB] #I name of environment variable
+char value[ARB] #I value of environment variable
+
+pointer sp, buf, op
+int node, junk, ch
+int gstrcpy(), ki_send()
+bool streq()
+
+include "kii.com"
+include "kinode.com"
+define quit_ 91
+
+begin
+ # Do not propagate the host-specific iraf definitions "iraf", "host",
+ # and "tmp" over the network.
+
+ ch = name[1]
+ if (ch == 'i' || ch == 'h' || ch == 't')
+ if (streq(name,"iraf") || streq(name,"host") || streq(name,"tmp"))
+ return
+
+ call smark (sp)
+ call salloc (buf, SZ_COMMAND, TY_CHAR)
+
+ # Format the SET statement to be sent to each node.
+ op = buf + gstrcpy ("set ", Memc[buf], SZ_COMMAND)
+ op = op + gstrcpy (name, Memc[op], SZ_COMMAND - 4)
+ Memc[op] = '='; op = op + 1
+ Memc[op] = '"'; op = op + 1
+ op = op + gstrcpy (value, Memc[op], SZ_COMMAND - (op - buf))
+ Memc[op] = '"'; op = op + 1
+ Memc[op] = '\n'; op = op + 1
+ Memc[op] = EOS
+
+ # Transmit the SET statement to each node currently running a kernel
+ # server process. This is done without reading back a status value
+ # to permit pipelining of multiple set environment packets.
+
+ for (node=1; node <= n_nnodes; node=node+1) {
+ if (n_kschan[node] == NULL)
+ next
+
+ # Set up control packet.
+ p_sbuflen = gstrcpy (Memc[buf], p_sbuf, SZ_SBUF)
+ p_arg[1] = p_sbuflen
+
+ # Transmit packet.
+ if (ki_send (node, KI_ENVINIT, 0) == ERR)
+ goto quit_
+ }
+
+ call sfree (sp)
+ return
+quit_
+ call zclsks (n_kschan[node], junk)
+ n_kschan[node] = NULL
+ call sfree (sp)
+end
diff --git a/sys/ki/kierror.x b/sys/ki/kierror.x
new file mode 100644
index 00000000..159b0707
--- /dev/null
+++ b/sys/ki/kierror.x
@@ -0,0 +1,66 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include "ki.h"
+
+# KI_ERROR -- Called when an i/o error occurs on the channel to a remote
+# kernel server process. Note that this is not the same as an i/o error
+# on a channel accessed on the remote node via the KI; when we are called
+# we assume that further communications with the kernel server are impossible.
+#
+# Error recover strategy:
+#
+# We shut down the ZFIOKS channel to the server and set the error bit in the
+# status word for the node. Note that we cannot return the node descriptor
+# until all of the remote OS channels (pids, etc.) multiplexed to the remote
+# node are closed on the local, client node. Any further i/o requests on the
+# node will cause ERR to be returned without any attempt to do i/o. A connect
+# request on the node will cause another kernel server to be spawned and
+# another node descriptor to be allocated. If and when all kichan descriptors
+# using the bad node are freed, the node descriptor will be freed.
+
+procedure ki_error (server)
+
+int server # kernel server node
+
+int junk, node, i
+int or(), and()
+include "kinode.com"
+
+begin
+ # Close the kernel server channel and set the error bit in the
+ # node descriptor.
+
+ call zclsks (n_kschan[server], junk)
+ n_status[server] = or (n_status[server], F_IOERR)
+
+ # Allocate a new node descriptor for use by the next connection
+ # on the node. If a node descriptor on which an error has occurred
+ # is later freed the F_REUSE bit will have been set in the status
+ # word (and the other bits cleared) so that we may reuse the
+ # descriptor.
+
+ node = 0
+ do i = 1, n_nnodes
+ if (and (n_status[i], F_REUSE) != 0) {
+ node = i
+ break
+ }
+ if (node == 0) {
+ n_nnodes = n_nnodes + 1
+ if (n_nnodes > MAX_NODES)
+ return
+ node = n_nnodes
+ }
+
+ # Initialize the new node descriptor. It is not necessary to transfer
+ # the n_local index since an i/o error cannot occur on the local node.
+
+ n_kschan[node] = NULL
+ n_status[node] = 0
+ n_nalias[node] = n_nalias[server]
+
+ call strcpy (n_server[1,server], n_server[1,node], SZ_SERVER)
+ do i = 1, n_nalias[node]
+ call strcpy (n_alias[1,i,server], n_alias[1,i,node], SZ_ALIAS)
+end
diff --git a/sys/ki/kiextnode.x b/sys/ki/kiextnode.x
new file mode 100644
index 00000000..672fcbc4
--- /dev/null
+++ b/sys/ki/kiextnode.x
@@ -0,0 +1,50 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "ki.h"
+
+# KI_EXTNODE -- Extract the node name prefix from a resource name of the form
+# "node!resource". The entire prefix is returned, i.e., "node!". The number
+# of chars in the prefix string is returned as the function value; zero is
+# returned if there is no node prefix. The name of the node owning the named
+# resource is returned in the output string. If no node is named in the
+# resource name supplied, the name of the default node (usually the local or
+# host node) is returned instead. Note that the function value refers to the
+# prefix string, not the string length of the nodename string.
+
+int procedure ki_extnode (resource, nodename, maxch, nchars)
+
+char resource[ARB] # name of a resource, with opt. node prefix
+char nodename[maxch] # receives node name
+int maxch # max chars out
+int nchars # receives nchars in nodename string
+
+char alias[SZ_ALIAS]
+int delim, op, junk, node
+int ki_gnode(), ki_findnode(), gstrcpy()
+include "kinode.com"
+
+begin
+ # Extract node name prefix, if any, and replace by primary alias.
+ junk = ki_gnode (resource, alias, delim)
+ if (delim > 0) {
+ node = ki_findnode (alias)
+ if (node > 0)
+ op = gstrcpy (n_alias[1,1,node], nodename, maxch) + 1
+ else
+ op = gstrcpy (alias, nodename, maxch) + 1
+ } else
+ op = 1
+
+ # Append the node prefix delimiter character.
+ if (op > 1 && op <= maxch) {
+ nodename[op] = FNNODE_CHAR
+ op = op + 1
+ nodename[op] = EOS
+ }
+
+ nodename[op] = EOS
+ nchars = op - 1
+
+ return (delim)
+end
diff --git a/sys/ki/kifchan.x b/sys/ki/kifchan.x
new file mode 100644
index 00000000..199212b2
--- /dev/null
+++ b/sys/ki/kifchan.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include "ki.h"
+
+# KI_FREECHAN -- Free a channel descriptor slot. Decrement the reference
+# count on the associated node descriptor slot; when the ref count reaches
+# zero, free the node descriptor if the error bit is set. If the error
+# bit is not set the node descriptor is not freed because the kernel server
+# remains connected, ready for reuse.
+
+procedure ki_freechan (chan)
+
+int chan # kichan channel descriptor
+
+int server, and()
+include "kichan.com"
+include "kinode.com"
+
+begin
+ server = k_node[chan]
+
+ # Server=0 if local node.
+ if (server > 0) {
+ n_nrefs[server] = n_nrefs[server] - 1
+ if (and (n_status[server], F_IOERR) != 0)
+ if (n_nrefs[server] == 0)
+ n_status[server] = F_IOERR + F_REUSE
+ }
+
+ k_oschan[chan] = NULL
+end
diff --git a/sys/ki/kifmapfn.x b/sys/ki/kifmapfn.x
new file mode 100644
index 00000000..3869f7c4
--- /dev/null
+++ b/sys/ki/kifmapfn.x
@@ -0,0 +1,38 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <mach.h>
+include "ki.h"
+
+# KI_FMAPFN -- Fully resolve a filename into its host equivalent, regardless
+# of the node on which the file resides. This is a temporary routine.
+# The filename mapping primitives should probably perform their function when
+# called for a remote file, rather than defer the mapping until later as they
+# do now. When this is changed, this routine will no longer be necessary and
+# can be removed. The output filename is returned as a packed filename with
+# the node name stripped, as for FMAPFN.
+
+procedure ki_fmapfn (vfn, pkosfn, maxch)
+
+char vfn[ARB] # network filename
+char pkosfn[maxch] # receives packed, fully resolved OS filename
+int maxch
+
+int server
+int ki_connect(), ki_sendrcv()
+include "kii.com"
+
+begin
+ call strpak (vfn, pkosfn, maxch)
+ server = ki_connect (pkosfn)
+
+ if (server == NULL)
+ call fmapfn (vfn, pkosfn, maxch)
+ else {
+ p_arg[2] = maxch
+ if (ki_sendrcv (server, KI_FMAPFN, 0) == ERR)
+ call syserrs (SYS_FNOSUCHFILE, vfn)
+ else
+ call strpak (p_sbuf, pkosfn, maxch)
+ }
+end
diff --git a/sys/ki/kifndnode.x b/sys/ki/kifndnode.x
new file mode 100644
index 00000000..f41e7197
--- /dev/null
+++ b/sys/ki/kifndnode.x
@@ -0,0 +1,40 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "ki.h"
+
+# KI_FINDNODE -- Given an alias for a node, search the node descriptor table
+# and return the table index of the named node or NULL.
+
+int procedure ki_findnode (alias)
+
+char alias[ARB] # alias to search for
+
+int node, i
+char first_char
+bool streq()
+int ki_gethosts(), ki_mapname(), and()
+include "kinode.com"
+
+begin
+ # Read the host name table if it has not been read yet.
+ if (n_nnodes == 0)
+ if (ki_gethosts() == ERR)
+ return (NULL)
+
+ # Map possible logical node name.
+ if (ki_mapname (alias, n_nodename, SZ_ALIAS) <= 0)
+ call strcpy (alias, n_nodename, SZ_ALIAS)
+
+ # Search the node descriptor table for a node with the given alias.
+ # Do not use descriptors that have the IOERR flag set.
+
+ first_char = n_nodename[1]
+ for (node=1; node <= n_nnodes; node=node+1)
+ for (i=1; i <= n_nalias[node]; i=i+1)
+ if (first_char == n_alias[1,i,node])
+ if (streq (n_nodename, n_alias[1,i,node]))
+ if (and (n_status[node], F_IOERR) == 0)
+ return (node)
+
+ return (NULL)
+end
diff --git a/sys/ki/kigchan.x b/sys/ki/kigchan.x
new file mode 100644
index 00000000..aa7c4332
--- /dev/null
+++ b/sys/ki/kigchan.x
@@ -0,0 +1,38 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include "ki.h"
+
+# KI_GETCHAN -- Find the first empty slot in the channel descriptor table
+# and return its index, initializing the server and oschan fields with the
+# values given.
+
+int procedure ki_getchan (server, oschan)
+
+int server # kernel server node
+int oschan # os channel (iraf kernel channel)
+
+int i
+include "kichan.com"
+include "kinode.com"
+
+begin
+ # Server=0 if local node.
+ if (server > 0)
+ n_nrefs[server] = n_nrefs[server] + 1
+
+ do i = FIRST_CHAN, MAX_CHANNELS
+ if (k_oschan[i] == NULL) {
+ # Initialize channel descriptor.
+
+ k_node[i] = server
+ k_oschan[i] = oschan
+ k_status[i] = 0
+ k_bufp[i] = NULL
+
+ return (i)
+ }
+
+ # The following cannot happen unless something is very wrong.
+ call sys_panic (0, "ki_getchan: out of channel slots")
+end
diff --git a/sys/ki/kighost.x b/sys/ki/kighost.x
new file mode 100644
index 00000000..31bebc0f
--- /dev/null
+++ b/sys/ki/kighost.x
@@ -0,0 +1,156 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "ki.h"
+
+# KI_GETHOSTS -- Read the host name table (file) and initialize the node
+# descriptor table (common). The default hosts table is the file "dev$hosts";
+# a different file may be specified with the environment variable
+# "irafhostnametable".
+
+int procedure ki_gethosts()
+
+pointer sp, lbuf, osfn, ip
+int chan, node, ch, op, junk, n, status, i, delim
+
+bool streq()
+int ctowrd(), envfind(), ki_gnode()
+include "kinode.com"
+
+begin
+ call smark (sp)
+ call salloc (osfn, SZ_PATHNAME, TY_CHAR)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ # Null selected node descriptor fields.
+ call aclri (n_kschan, MAX_NODES)
+ call aclri (n_nrefs, MAX_NODES)
+ call aclri (n_status, MAX_NODES)
+
+ # Process the host name table, ignoring blank lines and comment lines,
+ # until EOF is reached or the maximum number of nodes is exceeded.
+ # The format of a line is the server name followed by the aliases.
+ # Since this is a startup we require that the table file reside on
+ # the local node (not absolutely necessary, but it simplifies things).
+ # Note that since we are called by a z-routine at file open time,
+ # we cannot use high level file i/o to read the HNT file without
+ # reentrancy problems.
+
+ if (envfind (HNT_ENVNAME, Memc[osfn], SZ_PATHNAME) <= 0) {
+ if (envfind ("iraf", Memc[osfn], SZ_PATHNAME) <= 0) {
+ call sfree (sp)
+ return (ERR)
+ }
+
+ # Strip any node prefix from the iraf$ pathname; it had better
+ # reference the local node.
+
+ junk = ki_gnode (Memc[osfn], Memc[lbuf], delim)
+ if (delim > 0)
+ call strcpy (Memc[osfn+delim], Memc[osfn], SZ_PATHNAME)
+
+ # Form filename "iraf$subdir/file".
+ call zfsubd (Memc[osfn], SZ_PATHNAME, HNT_SUBDIR, junk)
+ call strcat (HNT_FILENAME, Memc[osfn], SZ_PATHNAME)
+ }
+
+ # Open the table file, a text file.
+ call strpak (Memc[osfn], Memc[osfn], SZ_PATHNAME)
+ call zopntx (Memc[osfn], READ_ONLY, chan)
+ if (chan == ERR) {
+ call sfree (sp)
+ return (ERR)
+ }
+
+ for (node=0; node < MAX_NODES; ) {
+ call zgettx (chan, Memc[lbuf], SZ_LINE, status)
+ if (status > 0)
+ Memc[lbuf+status] = EOS
+ else
+ break
+
+ # Get the next nonempty, noncomment line.
+ for (ip=lbuf; IS_WHITE(Memc[ip]); ip=ip+1)
+ ;
+ ch = Memc[ip]
+ if (ch == '\n' || ch == '#' || ch == EOS)
+ next
+
+ node = node + 1
+
+ # Extract the whitespace delimited alias names. The list of
+ # aliases is terminated by a colon.
+
+ n_nalias[node] = 0
+ n = 1
+
+ while (ctowrd (Memc, ip, n_alias[1,n,node], SZ_ALIAS) > 0) {
+ while (IS_WHITE (Memc[ip]))
+ ip = ip + 1
+
+ if (Memc[ip] == ':') {
+ ip = ip + 1
+ n_nalias[node] = n
+ break
+ } else
+ n = min (MAX_ALIAS, n + 1)
+ }
+
+ while (IS_WHITE (Memc[ip]))
+ ip = ip + 1
+
+ # Extract the kernel server name for the node. The server name
+ # string may contain whitespace and is delimited by end of line.
+
+ for (op=1; op <= SZ_SERVER; op=op+1) {
+ ch = Memc[ip]
+ if (ch == '\n' || ch == EOS)
+ break
+
+ n_server[op,node] = ch
+ ip = ip + 1
+ }
+
+ # Strip any trailing whitespace.
+ while (op > 1 && IS_WHITE(n_server[op-1,node]))
+ op = op - 1
+
+ # Make sure the server string is null terminated.
+ n_server[op,node] = EOS
+ }
+
+ n_nnodes = node
+ call zclstx (chan, status)
+
+ # Flag the local node. One of the aliases must match the name returned
+ # by ZGHOST else the local node will be accessed like a remote node
+ # (you may wish to take advantage of that for debugging). The default
+ # node name is initialized to the local node.
+
+ n_local = 0
+ n_default = 0
+
+ call strcpy (n_localnode, n_defaultnode, SZ_ALIAS)
+
+ for (node=1; node <= n_nnodes; node=node+1)
+ for (i=1; i <= n_nalias[node]; i=i+1)
+ if (streq (n_alias[1,i,node], n_localnode)) {
+ n_local = node
+ n_default = node
+ break
+ }
+
+ if (n_local > 0) {
+ # Add the alias "0" to the alias list for this node. This is a
+ # required alias and will overwrite the last alias for the node
+ # if the alias list is full.
+
+ n = n_nalias[n_local]
+ n = min (MAX_ALIAS, n + 1)
+ n_nalias[n_local] = n
+ call strcpy ("0", n_alias[1,n,n_local], SZ_ALIAS)
+ }
+
+ call sfree (sp)
+ return (n_nnodes)
+end
diff --git a/sys/ki/kignode.x b/sys/ki/kignode.x
new file mode 100644
index 00000000..96424eff
--- /dev/null
+++ b/sys/ki/kignode.x
@@ -0,0 +1,111 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <chars.h>
+include "ki.h"
+
+# KI_GNODE -- Extract the node name prefix from a resource name. The node
+# name delimiter character may be escaped to be included in the resource name.
+# If the resource name does not include an explicit node name the name of the
+# default node is returned. The function value is LOCAL if the resource resides
+# on the local node. NOTE: We can be called before initialization of the
+# node descriptor table.
+
+int procedure ki_gnode (rname, outstr, delim)
+
+char rname[ARB] # resource name
+char outstr[SZ_ALIAS] # receives node name
+int delim # receives offset of delim char
+
+int ch, nchars
+int ip, op, off, i
+bool streq()
+int ki_mapname()
+include "kinode.com"
+define lookup_ 91
+
+begin
+ nchars = 0
+ delim = 0
+ op = 1
+
+ # Skip leading whitespace.
+ for (off=1; IS_WHITE (rname[off]); off=off+1)
+ ;
+
+ # If the first char is the node char, there can be no node prefix.
+ if (rname[off] == FNNODE_CHAR) {
+ outstr[1] = EOS
+ return (LOCAL)
+ }
+
+ # Extract explicit node name if given.
+ do ip = off, off + SZ_ALIAS {
+ ch = rname[ip]
+
+ if (!IS_LOWER(ch) || !IS_DIGIT(ch))
+ if (ch == EOS)
+ break
+ else if (ch == FNNODE_CHAR) {
+ if (rname[ip-1] != '\\') {
+ # Have node name.
+ delim = ip
+ nchars = (op - 1)
+ goto lookup_
+ } else
+ op = max (1, op - 1)
+ }
+
+ outstr[op] = ch
+ op = op + 1
+ }
+
+ # No explicit node name given; use default node name.
+ do i = 1, SZ_ALIAS + 1 {
+ outstr[i] = n_defaultnode[i]
+ if (outstr[i] == EOS) {
+ nchars = (i - 1)
+ break
+ }
+ }
+
+
+lookup_
+ outstr[nchars+1] = EOS
+
+ # Determine if the named node is the local or a remote node. This must
+ # work during process startup, before the network tables have been read,
+ # or when networking is enabled but the tables have not beed edited for
+ # a new host (in which case there will be no entry in the tables for
+ # the local node as identified by ZGHOST).
+
+ if (nchars <= 0) {
+ # No output node name.
+ outstr[1] = EOS
+ return (LOCAL)
+
+ } else if (n_local == NULL) {
+ # If local node is not identified in the host name table, this
+ # effectively disables networking. All nodes names are assumed
+ # to be local.
+
+ return (LOCAL)
+
+ } else {
+ # We have a node name and the local node is identified in the
+ # node table. Scan the aliases of the local node to see if the
+ # referenced node is the same.
+
+ # Map possible logical node name.
+ if (ki_mapname (outstr, n_nodename, SZ_ALIAS) <= 0)
+ call strcpy (outstr, n_nodename, SZ_ALIAS)
+
+ ch = n_nodename[1]
+ do i = 1, n_nalias[n_local]
+ if (n_alias[1,i,n_local] == ch)
+ if (streq (n_alias[1,i,n_local], n_nodename))
+ return (LOCAL)
+ }
+
+ return (REMOTE)
+end
diff --git a/sys/ki/kii.com b/sys/ki/kii.com
new file mode 100644
index 00000000..cd542b3d
--- /dev/null
+++ b/sys/ki/kii.com
@@ -0,0 +1,15 @@
+# KI common -- Contains both the packed and unpacked packet used to transmit
+# and receive requests over the network. Since the packed packet is first
+# in the common any overflow due to failure of the assumptions about the
+# size of the packed packet in host ints will only damage the area used by
+# the unpacked packet, causing no harm.
+
+int p_packet[SZB_PACKET/SZB_CHAR/SZ_MII_INT] # packed packet
+
+int p_opcode # instruction opcode
+int p_subcode # subcode, if device driver
+int p_arg[MAX_ARGS] # procedure arguments
+int p_sbuflen # nchars in use in string buffer
+char p_sbuf[SZ_SBUF] # string buffer
+
+common /kiicom/ p_packet, p_opcode, p_subcode, p_arg, p_sbuflen, p_sbuf
diff --git a/sys/ki/kiinit.x b/sys/ki/kiinit.x
new file mode 100644
index 00000000..1d7488cb
--- /dev/null
+++ b/sys/ki/kiinit.x
@@ -0,0 +1,67 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include "ki.h"
+
+# KI_INIT -- Called by the IRAF Main during process startup to initialize
+# the kernel interface to the process i/o channels. INCHAN, OUTCHAN, and
+# ERRCHAN are the host system i/o channel codes for the process standard
+# input, output, and error channels. DEVICE is a ZLOCPR entry point address
+# (kernel level) identifing the device driver to be used. To use the KI we
+# must allocate channel descriptors for the host system i/o channels, and
+# the device entry point address must be mapped to the corresponding KI
+# procedure.
+
+procedure ki_init (inchan, outchan, errchan, device, devtype)
+
+int inchan #RW process input channel
+int outchan #RW process output channel
+int errchan #RW process error output channel
+int device #RW device driver epa
+int devtype #R device type (not modified)
+
+int locpr()
+extern zgettx(), zgetty(), zardbf(), zardpr()
+extern kgettx(), kgetty(), kardbf(), kardpr()
+include "kichan.com"
+include "kinode.com"
+
+begin
+ # Initialize the ki channel descriptors.
+ call amovki (NULL, k_oschan, MAX_CHANNELS)
+ call amovki (ERR, k_status, MAX_CHANNELS)
+
+ # Assign KI channels for the 3 OS channels.
+
+ k_node[1] = NULL
+ k_oschan[1] = inchan
+ inchan = 1
+
+ k_node[2] = NULL
+ k_oschan[2] = outchan
+ outchan = 2
+
+ k_node[3] = NULL
+ k_oschan[3] = errchan
+ errchan = 3
+
+ # Map device codes.
+
+ if ( device == locpr (zgettx))
+ device = locpr (kgettx)
+ else if (device == locpr (zgetty))
+ device = locpr (kgetty)
+ else if (device == locpr (zardbf))
+ device = locpr (kardbf)
+ else if (device == locpr (zardpr))
+ device = locpr (kardpr)
+
+ # Initialize node descriptor.
+
+ call zghost (n_localnode, SZ_ALIAS)
+ call strupk (n_localnode, n_localnode, SZ_ALIAS)
+
+ n_defaultnode[1] = EOS
+ n_default = NULL
+ n_local = NULL
+end
diff --git a/sys/ki/kilnode.x b/sys/ki/kilnode.x
new file mode 100644
index 00000000..e332e8f0
--- /dev/null
+++ b/sys/ki/kilnode.x
@@ -0,0 +1,41 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "ki.h"
+
+# KI_LOCALNODE -- Determine if the named node is the local node.
+
+int procedure ki_localnode (node)
+
+char node[ARB] # node name
+
+int ch, i
+bool streq()
+int ki_mapname()
+include "kinode.com"
+
+begin
+ if (n_local == NULL) {
+ # If local node is not identified in the host name table, this
+ # effectively disables networking. All nodes names are assumed
+ # to be local.
+
+ return (YES)
+
+ } else {
+ # We have a node name and the local node is identified in the
+ # node table. Scan the aliases of the local node to see if the
+ # referenced node is the same.
+
+ # Map possible logical node name.
+ if (ki_mapname (node, n_nodename, SZ_ALIAS) <= 0)
+ call strcpy (node, n_nodename, SZ_ALIAS)
+
+ ch = n_nodename[1]
+ do i = 1, n_nalias[n_local]
+ if (n_alias[1,i,n_local] == ch)
+ if (streq (n_alias[1,i,n_local], n_nodename))
+ return (YES)
+ }
+
+ return (NO)
+end
diff --git a/sys/ki/kimapchan.x b/sys/ki/kimapchan.x
new file mode 100644
index 00000000..196619d2
--- /dev/null
+++ b/sys/ki/kimapchan.x
@@ -0,0 +1,44 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include <mach.h>
+include <knet.h>
+include "ki.h"
+
+# KI_MAPCHAN -- Return the OS channel number or pid and the node name of the
+# resource associated with a given KI channel. This procedure may be called
+# whether or not networking is enabled.
+
+int procedure ki_mapchan (chan, nodename, maxch)
+
+int chan # KI channel (ret. by kopnbf, etc.)
+char nodename[maxch] # receives node name
+int maxch
+
+int node
+bool netenab
+data netenab /KNET/
+include "kichan.com"
+include "kinode.com"
+
+begin
+ if (netenab) {
+ # Networking is enabled. Every channel or pid returned to the VOS
+ # by the kernel is actually a KI channel index.
+
+ node = k_node[chan]
+ if (node == NULL || n_nnodes == 0)
+ call strcpy (n_localnode, nodename, maxch)
+ else
+ call strcpy (n_alias[1,1,node], nodename, maxch)
+
+ return (k_oschan[chan])
+
+ } else {
+ # Networking is disabled. Return the name of the local node
+ # and return the channel argument unchanged.
+
+ call strcpy (n_localnode, nodename, maxch)
+ return (chan)
+ }
+end
diff --git a/sys/ki/kimapname.x b/sys/ki/kimapname.x
new file mode 100644
index 00000000..53d5deb2
--- /dev/null
+++ b/sys/ki/kimapname.x
@@ -0,0 +1,38 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# KI_MAPNAME -- Map a logical node name to a literal node name. Logical
+# node names may be defined in the environment as aliases for "hardcoded"
+# hosts-file node names. To distinguish logical node names from other
+# environment variables the value string must end in the node delimiter
+# character "!". For example, "set alpha = foo.bar.edu!" defines logical
+# node alpha to be the same as foo.tar.edu. The "!" suffix also allows
+# the logical node name to be used in file references, e.g. "alpha!pathname".
+#
+# If the input name is a logical node name the translated value is returned
+# in newname and the number of characters output is returned as the function
+# value (as for envfind). If the input name is not a logical node name
+# zero is returned as the function value.
+#
+# It might make sense to allow multiple indirection on name translations,
+# but this is not currently supported.
+
+int procedure ki_mapname (name, newname, maxch)
+
+char name[ARB] #I input logical node name
+char newname[ARB] #O output translated name
+int maxch #I max chars out
+
+int nchars
+int envfind()
+
+begin
+ nchars = envfind (name, newname, maxch)
+ if (nchars > 1)
+ if (newname[nchars] == '!') {
+ newname[nchars] = EOS
+ return (nchars - 1)
+ }
+
+ newname[1] = EOS
+ return (0)
+end
diff --git a/sys/ki/kinode.com b/sys/ki/kinode.com
new file mode 100644
index 00000000..2e0e9a16
--- /dev/null
+++ b/sys/ki/kinode.com
@@ -0,0 +1,18 @@
+# KINODE.COM -- Node descriptor table. Contains one entry for each node listed
+# in the host name table file.
+
+int n_nnodes # number of nodes in table
+int n_local # index of the local node
+int n_default # index of the current defnode
+int n_kschan[MAX_NODES] # server channel (init to NULL)
+int n_nrefs[MAX_NODES] # number of k_oschan using node
+int n_status[MAX_NODES] # status bits for channel
+int n_nalias[MAX_NODES] # number of aliases
+char n_localnode[SZ_ALIAS] # name of the local node
+char n_defaultnode[SZ_ALIAS] # name of the default node
+char n_nodename[SZ_ALIAS] # node name working storage
+char n_server[SZ_SERVER,MAX_NODES] # kernel server names
+char n_alias[SZ_ALIAS,MAX_ALIAS,MAX_NODES] # aliases for the node
+
+common /kinode/ n_nnodes, n_local, n_default, n_kschan, n_nrefs, n_status,
+ n_nalias, n_localnode, n_defaultnode, n_nodename, n_server, n_alias
diff --git a/sys/ki/kintpr.x b/sys/ki/kintpr.x
new file mode 100644
index 00000000..ec3b6d4f
--- /dev/null
+++ b/sys/ki/kintpr.x
@@ -0,0 +1,36 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KINTPR -- Send a signal (interrupt) to a connected subprocess.
+
+procedure kintpr (pid, vex, status)
+
+int pid # process id
+int vex # virtual exception
+int status # exit status of the job
+
+int server
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = k_node[pid]
+
+ if (server == NULL) {
+ call zintpr (k_oschan[pid], vex, status)
+
+ } else {
+ p_arg[1] = k_oschan[pid]
+ p_arg[2] = vex
+ p_sbuflen = 0
+
+ if (ki_sendrcv (server, KI_ZINTPR, 0) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+ }
+end
diff --git a/sys/ki/kiopenks.x b/sys/ki/kiopenks.x
new file mode 100644
index 00000000..64bfb626
--- /dev/null
+++ b/sys/ki/kiopenks.x
@@ -0,0 +1,133 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <chars.h>
+include "ki.h"
+
+# KI_OPENKS -- Physically open a kernel server process on a remote node.
+# Spawn the process and initialize the environment list and iraf root
+# directory on the remote node. The KS channel or NULL is returned as the
+# function value.
+
+int procedure ki_openks (node)
+
+int node # node descriptor to open kernel on
+
+bool hostdep
+pointer sp, ksname, env, el, valp, ip, op, sv
+int show, kschan, nchars, status, junk
+
+pointer env_first(), env_next()
+int strlen(), stridx(), strncmp()
+int gstrcpy(), ki_send(), ki_receive()
+
+data show /NO/
+include "kii.com"
+include "kinode.com"
+define quit_ 91
+
+begin
+ call smark (sp)
+ call salloc (ksname, SZ_FNAME, TY_CHAR)
+ call salloc (sv, SZB_PACKET / SZB_CHAR, TY_CHAR)
+
+ status = ERR
+
+ # Our caller may have already prepped a packet in the kii common, which
+ # we are going to clobber below. Save packet and restore when done.
+
+ call amovc (FIRSTINTFIELD, Memc[sv], SZB_PACKET / SZB_CHAR)
+
+ # Spawn the kernel server process.
+
+ call strpak (n_server[1,node], Memc[ksname], SZ_FNAME)
+ call zopnks (Memc[ksname], READ_WRITE, kschan)
+ if (kschan == ERR) {
+ call sfree (sp)
+ return (ERR)
+ } else
+ n_kschan[node] = kschan
+
+ # Read the environment list into a string buffer. Scan the list once
+ # to determine its size, then allocate the buffer and format a series
+ # of "set name=value" lines in the buffer.
+ # Note 4 + 1 comes from len("set ") + \n.
+
+ nchars = 0
+ for (el=env_first(valp); el != NULL; el=env_next(el,valp,show))
+ nchars = nchars + strlen (Memc[valp]) + 4 + 2 + 1
+
+ call salloc (env, nchars, TY_CHAR)
+
+ op = env
+ for (el=env_first(valp); el != NULL; el=env_next(el,valp,show)) {
+ # Do not pass on the values of the host dependent environment
+ # variables HOST, IRAF, and TMP. If we do not set the values
+ # here, the remote kernel will fetch the values automatically
+ # from the HSI global include file <iraf.h> on the server node.
+
+ hostdep = false
+ if (stridx (Memc[valp], "hit") > 0)
+ hostdep = ((strncmp (Memc[valp], "host=", 5) == 0) ||
+ (strncmp (Memc[valp], "iraf=", 5) == 0) ||
+ (strncmp (Memc[valp], "tmp=", 4) == 0))
+
+ if (!hostdep) {
+ call strcpy ("set ", Memc[op], ARB)
+ op = op + 4
+ for (ip=valp; Memc[ip] != '='; ip=ip+1) {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ Memc[op] = '='; op = op + 1
+ Memc[op] = '"'; op = op + 1
+ op = op + gstrcpy (Memc[ip+1], Memc[op], ARB)
+ Memc[op] = '"'; op = op + 1
+ Memc[op] = '\n'; op = op + 1
+ }
+ }
+
+ Memc[op] = EOS
+
+ # Transmit the environment list to the server process, preceded by the
+ # KI_ENVINIT instruction packet. The ENVINIT function does not return
+ # a status (to permit pipelining of multiple setenv packets).
+
+ p_arg[1] = nchars
+ if (nchars <= SZ_SBUF)
+ call strcpy (Memc[env], p_sbuf, nchars)
+
+ if (ki_send (node, KI_ENVINIT, 0) == ERR)
+ goto quit_
+
+ if (nchars > SZ_SBUF) {
+ # Transmit the data record.
+ call strpak (Memc[env], Memc[env], nchars)
+ call zawrks (kschan, Memc[env], nchars, long(0))
+ call zawtks (kschan, status)
+ if (status != nchars) {
+ status = ERR
+ goto quit_
+ }
+
+ # We do expect a status return for large packets.
+ if (ki_receive (node, KI_ENVINIT, 0) == ERR)
+ goto quit_
+ if (p_arg[1] == ERR)
+ goto quit_
+ }
+
+ status = OK
+quit_
+ if (status == ERR) {
+ call zclsks (kschan, junk)
+ n_kschan[node] = NULL
+ }
+
+ # Restore the caller's kii packet.
+ call amovc (Memc[sv], FIRSTINTFIELD, SZB_PACKET / SZB_CHAR)
+
+ call sfree (sp)
+ return (status)
+end
diff --git a/sys/ki/kireceive.x b/sys/ki/kireceive.x
new file mode 100644
index 00000000..2cd1e7b6
--- /dev/null
+++ b/sys/ki/kireceive.x
@@ -0,0 +1,71 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <ctype.h>
+include "ki.h"
+
+# KI_RECEIVE -- Read a machine independent KII packet from the network
+# interface and decode it into the internal, machine dependent form in the
+# kii common. An error status is returned if the opcode and subcode in
+# the packet do not match those expected, or if an i/o error occurs on the
+# channel.
+
+int procedure ki_receive (server, opcode, subcode)
+
+int server # node index of server process
+int opcode # function opcode
+int subcode # function subcode (for drivers)
+
+int stat, ip, op, ch
+int gstrcpy()
+include "kii.com"
+include "kinode.com"
+
+begin
+ # Read the packet.
+ call ks_aread (server, p_packet, SZB_PACKET)
+ call ks_await (server, stat)
+
+ # Hard error on the channel to the kernel server.
+ if (stat == ERR)
+ return (ERR)
+
+ # The encoded packet consists of LEN_INTFIELDS 32 bit MII integers
+ # followed by p_sbuflen chars, one char per byte.
+
+ call miiupk32 (p_packet, FIRSTINTFIELD, LEN_INTFIELDS, TY_INT)
+ call chrupk (p_packet, LEN_INTFIELDS * 4 + 1, p_sbuf, 1,
+ max(0, min(SZ_SBUF, p_sbuflen)) + 1)
+
+ # Check for out of band data, i.e., the data read was not a packet
+ # but some unsolicited message, e.g., error message, from the
+ # called program. If this happens, print the error message and
+ # return an error status.
+
+ if (stat != SZB_PACKET || p_opcode != opcode || p_subcode != subcode) {
+
+ # Is it a printable string? If so, print the message in the
+ # format "node: message".
+
+ op = gstrcpy (n_alias[1,1,server], p_sbuf, SZ_ALIAS) + 1
+ p_sbuf[op] = ':'
+ op = op + 1
+ p_sbuf[op] = ' '
+ op = op + 1
+ call chrupk (p_packet, 1, p_sbuf, op, SZ_LINE)
+
+ do ip = op, SZ_LINE {
+ ch = p_sbuf[ip]
+ if (ch == EOS)
+ break
+ else if (!IS_ASCII(ch))
+ call strcpy ("out of band data on ki channel\n", p_sbuf,
+ SZ_LINE)
+ }
+
+ call xer_putline (STDERR, p_sbuf)
+ return (ERR)
+
+ } else
+ return (OK)
+end
diff --git a/sys/ki/kisend.x b/sys/ki/kisend.x
new file mode 100644
index 00000000..5b3f17d4
--- /dev/null
+++ b/sys/ki/kisend.x
@@ -0,0 +1,33 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KI_SEND -- Encode the packet in the kii common in a machine independent form
+# and send it over the network.
+
+int procedure ki_send (server, opcode, subcode)
+
+int server # node index of server process
+int opcode # function opcode
+int subcode # function subcode (for drivers)
+
+int status
+include "kii.com"
+
+begin
+ p_opcode = opcode
+ p_subcode = subcode
+
+ # Encode the packet in machine independent form, i.e., LEN_INTFIELDS
+ # 32 bit MII integers followed by p_sbuflen chars, one char per byte.
+
+ call miipak32 (FIRSTINTFIELD, p_packet, LEN_INTFIELDS, TY_INT)
+ call chrpak (p_sbuf, 1, p_packet, LEN_INTFIELDS * 4 + 1, p_sbuflen + 1)
+
+ # Transmit the packet.
+ call ks_awrite (server, p_packet, SZB_PACKET)
+ call ks_await (server, status)
+
+ return (status)
+end
diff --git a/sys/ki/kisendrcv.x b/sys/ki/kisendrcv.x
new file mode 100644
index 00000000..8a319a35
--- /dev/null
+++ b/sys/ki/kisendrcv.x
@@ -0,0 +1,20 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# KI_SENDRCV -- Encode and send a packet to a remote server process, then
+# read and decode the response packet. The opcode and subcode in the
+# response packet must agree with those in the packet sent.
+
+int procedure ki_sendrcv (server, opcode, subcode)
+
+int server # os channel to server process
+int opcode # function opcode
+int subcode # function subcode (for drivers)
+
+int ki_send(), ki_receive()
+
+begin
+ if (ki_send (server, opcode, subcode) == ERR)
+ return (ERR)
+ else
+ return (ki_receive (server, opcode, subcode))
+end
diff --git a/sys/ki/kishownet.x b/sys/ki/kishownet.x
new file mode 100644
index 00000000..63765aee
--- /dev/null
+++ b/sys/ki/kishownet.x
@@ -0,0 +1,69 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+procedure ki_shownet (fd)
+
+int fd # output file
+
+int i, j, n
+int ki_gethosts()
+include "kinode.com"
+
+begin
+ if (n_nnodes == 0)
+ n = ki_gethosts()
+
+ call fprintf (fd, "Local node `%s' (%d), default node `%s', ")
+ call pargstr (n_localnode)
+ call pargi (n_local)
+ call pargstr (n_defaultnode)
+ call fprintf (fd, "%d nodes in local network\n")
+ call pargi (n_nnodes)
+
+ if (n_local == 0) {
+ call fprintf (fd, "Network interface disabled ")
+ call fprintf (fd, "(no entry for local node in dev$hosts)\n")
+ }
+
+ if (n_nnodes == MAX_NODES)
+ call fprintf (fd, "HOST NAME TABLE IS FULL\n")
+ else if (n_nnodes <= 0)
+ return
+
+ # Print node table.
+ call fprintf (fd, "\n NODE SERVER NREFS STATUS ALIASES\n")
+ do i = 1, n_nnodes {
+ call fprintf (fd, "%8d %6d %5d %05o ")
+ call pargi (i)
+ call pargi (n_kschan[i])
+ call pargi (n_nrefs[i])
+ call pargi (n_status[i])
+
+ do j = 1, n_nalias[i] {
+ call fprintf (fd, " %s")
+ call pargstr (n_alias[1,j,i])
+ }
+
+ call fprintf (fd, "\n")
+ }
+
+# The following should no longer be needed as ki_mapname and the
+# "node!" syntax should prevent accidential aliasing of node names
+# and non-network related environment variables.
+#
+# n = 0
+# do i = 1, n_nnodes
+# do j = 1, n_nalias[i]
+# if (envfind (n_alias[1,j,i], Memc[text], SZ_FNAME) > 0) {
+# if (n == 0)
+# call fprintf (fd, "\n")
+# call fprintf (fd,
+# "Warning: node name `%s' is an alias for `%s'\n")
+# call pargstr (n_alias[1,j,i])
+# call pargstr (Memc[text])
+# n = n + 1
+# }
+end
diff --git a/sys/ki/kixnode.x b/sys/ki/kixnode.x
new file mode 100644
index 00000000..acf2dec2
--- /dev/null
+++ b/sys/ki/kixnode.x
@@ -0,0 +1,31 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# KI_XNODE -- Transfer the node prefix, if any, from one resource string to
+# another. If the output resource already has a node prefix it is replaced
+# by the new one. The output resource string is modified in place. If the
+# output string is the null string the node prefix from the input string
+# is returned. If the input string is the null string the node prefix from
+# the output string is deleted, leaving only the resource name.
+
+procedure ki_xnode (r1, r2, maxch)
+
+char r1[ARB] #I input resource with optional node prefix
+char r2[ARB] #U output resource to append node! to
+int maxch #I max chars out
+
+pointer sp, rt
+int ip, nchars, buflen
+int ki_extnode(), strlen()
+
+begin
+ call smark (sp)
+ buflen = strlen(r2) + SZ_FNAME
+ call salloc (rt, buflen, TY_CHAR)
+
+ ip = ki_extnode (r2, Memc[rt], buflen, nchars) + 1
+ call strcpy (r2[ip], Memc[rt], buflen)
+ ip = ki_extnode (r1, r2, maxch, nchars)
+ call strcpy (Memc[rt], r2[nchars+1], maxch-nchars)
+
+ call sfree (sp)
+end
diff --git a/sys/ki/kopcpr.x b/sys/ki/kopcpr.x
new file mode 100644
index 00000000..21497992
--- /dev/null
+++ b/sys/ki/kopcpr.x
@@ -0,0 +1,47 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KOPCPR -- Open a connected subprocess.
+
+procedure kopcpr (process, inchan, outchan, pid)
+
+char process[ARB] # packed osfn of process executable
+int inchan, outchan # receives process input output channels
+int pid # receives process id
+
+int server
+int ki_connect(), ki_sendrcv(), ki_getchan()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = ki_connect (process)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopcpr (p_sbuf, inchan, outchan, pid)
+ } else {
+ if (ki_sendrcv (server, KI_ZOPCPR, 0) == ERR)
+ pid = ERR
+ else {
+ pid = p_arg[1]
+ inchan = p_arg[2]
+ outchan = p_arg[3]
+ }
+ }
+
+ # Allocate 3 channel descriptors, one for the each of the i/o
+ # channels and another for the PID. Save the channel descriptor
+ # numbers of the i/o channels in the status field of the PID
+ # descriptor to permit freeing the lot at disconnect time.
+
+ if (pid != ERR) {
+ pid = ki_getchan (server, pid)
+ inchan = ki_getchan (server, inchan)
+ outchan = ki_getchan (server, outchan)
+ k_status[pid] = inchan * MAX_CHANNELS + outchan
+ }
+end
diff --git a/sys/ki/kopdir.x b/sys/ki/kopdir.x
new file mode 100644
index 00000000..88ee950d
--- /dev/null
+++ b/sys/ki/kopdir.x
@@ -0,0 +1,50 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <diropen.h>
+include "ki.h"
+
+# KOPDIR -- Open a directory file for reading.
+
+procedure kopdir (osfn, chan)
+
+char osfn[ARB] # packed os filename or directory name
+int chan # channel assigned for reading filenames
+
+int server
+pointer dp
+int ki_connect(), ki_sendrcv(), ki_getchan(), kmalloc()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zopdir (p_sbuf, chan)
+
+ } else {
+ p_arg[2] = PASS_HIDDEN_FILES
+
+ if (ki_sendrcv (server, KI_ZOPDIR, 0) == ERR)
+ chan = ERR
+ else {
+ chan = p_arg[1]
+ if (kmalloc (dp, LEN_DIRBDES, TY_STRUCT) == ERR)
+ chan = ERR
+ else {
+ D_IP(dp) = D_DATA(dp)
+ D_ITOP(dp) = D_DATA(dp)
+ D_EOFSEEN(dp) = NO
+ }
+ }
+ }
+
+ if (chan != ERR) {
+ chan = ki_getchan (server, chan)
+ if (server != NULL)
+ k_bufp[chan] = dp
+ }
+end
diff --git a/sys/ki/kopdpr.x b/sys/ki/kopdpr.x
new file mode 100644
index 00000000..1ea62dc9
--- /dev/null
+++ b/sys/ki/kopdpr.x
@@ -0,0 +1,59 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "ki.h"
+
+# KOPDPR -- Open a detached process.
+
+procedure kopdpr (process, bkgfile, bkgmsg, jobcode)
+
+char process[ARB] # packed osfn of process executable
+char bkgfile[ARB] # packed osfn of bkg file
+char bkgmsg[ARB] # control string for kernel
+int jobcode # receives job code of process
+
+pointer sp, osfn, alias
+int server, off, delim
+int ki_connect(), ki_sendrcv(), ki_getchan(), strlen(), ki_gnode()
+include "kii.com"
+
+begin
+ call smark (sp)
+ call salloc (osfn, SZ_PATHNAME, TY_CHAR)
+ call salloc (alias, SZ_ALIAS, TY_CHAR)
+
+ server = ki_connect (process)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call strupk (bkgfile, Memc[osfn], SZ_PATHNAME)
+
+ # The bkg file must be on the same node as the process file.
+ if (ki_gnode (Memc[osfn], Memc[alias], delim) == REMOTE)
+ jobcode = ERR
+ else {
+ call strpak (Memc[osfn+(delim+1)-1], Memc[osfn], SZ_PATHNAME)
+ call zopdpr (p_sbuf, Memc[osfn], bkgmsg, jobcode)
+ }
+
+ } else {
+ # Spawning of detached processes on remote notes is not really
+ # supported as of yet. Add support for passing the bkgmsg; use
+ # node name in bkgmsg to submit bkg job to remote node.
+
+ off = p_sbuflen + 2
+ p_arg[2] = off
+ call strupk (bkgfile, p_sbuf[off], ARB)
+ p_sbuflen = off + strlen(p_sbuf[off])
+
+ if (ki_sendrcv (server, KI_ZOPDPR, 0) == ERR)
+ jobcode = ERR
+ else
+ jobcode = p_arg[1]
+ }
+
+ if (jobcode != ERR)
+ jobcode = ki_getchan (server, jobcode)
+
+ call sfree (sp)
+end
diff --git a/sys/ki/koscmd.x b/sys/ki/koscmd.x
new file mode 100644
index 00000000..6a358f8d
--- /dev/null
+++ b/sys/ki/koscmd.x
@@ -0,0 +1,108 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include <chars.h>
+include <ctype.h>
+include <mach.h>
+include "ki.h"
+
+# KOSCMD -- Send a command to the host command interpreter on the remote
+# node. The output is captured in a file and returned to the caller on
+# the local host.
+
+procedure koscmd (oscmd, stdin_file, stdout_file, stderr_file, status)
+
+char oscmd[ARB] # packed host command string
+char stdin_file[ARB] # packed filename of stdin file
+char stdout_file[ARB] # packed filename of stdout file
+char stderr_file[ARB] # packed filename of stderr file
+int status
+
+pointer sp, remfn, locfn, lbuf, op
+int server, oscmd_status, inchan, outchan, nchars
+int ki_connect(), ki_sendrcv(), gstrcpy()
+include "kinode.com"
+include "kii.com"
+
+begin
+ server = ki_connect (oscmd)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zoscmd (p_sbuf, stdin_file, stdout_file, stderr_file, status)
+
+ } else {
+ if (ki_sendrcv (server, KI_ZOSCMD, 0) == ERR)
+ status = ERR
+ else if (p_arg[1] == ERR)
+ status = ERR
+
+ else {
+ call smark (sp)
+ call salloc (remfn, SZ_PATHNAME, TY_CHAR)
+ call salloc (locfn, SZ_PATHNAME, TY_CHAR)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ oscmd_status = p_arg[1]
+
+ # Construct the network pathname of the remote spool file.
+ op = remfn + gstrcpy (n_alias[1,1,server], Memc[remfn], ARB)
+ Memc[op] = FNNODE_CHAR; op = op + 1
+ call strcpy (p_sbuf, Memc[op], ARB)
+ call strpak (Memc[remfn], Memc[remfn], SZ_PATHNAME)
+
+ # Open the spooled output file on the remote node.
+ call kopntx (Memc[remfn], READ_ONLY, inchan)
+ if (inchan == ERR) {
+ status = ERR
+ call sfree (sp)
+ return
+ }
+
+ # Open the output file on the local node. Currently, all
+ # output is sent to the designated stdout_file, and the other
+ # redirection files are ignored if specified. If no stdout
+ # file is specified, write directly to the user terminal.
+
+ call strupk (stdout_file, Memc[locfn], SZ_PATHNAME)
+ if (Memc[locfn] != EOS) {
+ # Copy to a textfile on the local node.
+
+ call zopntx (stdout_file, APPEND, outchan)
+ if (outchan == ERR) {
+ call kclstx (inchan, status)
+ status = ERR
+ call sfree (sp)
+ return
+ }
+
+ repeat {
+ call kgettx (inchan, Memc[lbuf], SZ_LINE, nchars)
+ if (nchars > 0)
+ call zputtx (outchan, Memc[lbuf], nchars, status)
+ } until (nchars <= 0)
+
+ call zclstx (outchan, status)
+
+ } else {
+ # Copy to the terminal on the local node, i.e., to the
+ # standard error output of the calling process.
+
+ repeat {
+ call kgettx (inchan, Memc[lbuf], SZ_LINE, nchars)
+ if (nchars > 0) {
+ Memc[lbuf+nchars] = EOS
+ call xer_putline (STDERR, Memc[lbuf])
+ }
+ } until (nchars <= 0)
+ }
+
+ # Close and delete the remote spool file.
+ call kclstx (inchan, status)
+ call kfdele (Memc[remfn], status)
+
+ status = oscmd_status
+ call sfree (sp)
+ }
+ }
+end
diff --git a/sys/ki/ksaread.x b/sys/ki/ksaread.x
new file mode 100644
index 00000000..824b1a67
--- /dev/null
+++ b/sys/ki/ksaread.x
@@ -0,0 +1,21 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "ki.h"
+
+# KS_AREAD -- Read from the kernel server device driver given the node
+# descriptor of a kernel server channel. If the error bit is set on the
+# node return error w/o doing any i/o, since the channel will have been closed.
+
+procedure ks_aread (server, buf, maxbytes)
+
+int server # node descriptor index of server
+char buf[ARB] # i/o buffer
+int maxbytes # maxbytes to read
+
+int and()
+include "kinode.com"
+
+begin
+ if (and (n_status[server], F_IOERR) == 0)
+ call zardks (n_kschan[server], buf, maxbytes, long(0))
+end
diff --git a/sys/ki/ksawait.x b/sys/ki/ksawait.x
new file mode 100644
index 00000000..069826d5
--- /dev/null
+++ b/sys/ki/ksawait.x
@@ -0,0 +1,24 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "ki.h"
+
+# KS_AWAIT -- Wait for i/o to the kernel server device driver given the node
+# descriptor of a kernel server channel. If the error bit is set on the
+# node return immediately, since the channel will have been closed.
+
+procedure ks_await (server, status)
+
+int server # node descriptor index of server
+int status # receives i/o status
+
+int and()
+include "kinode.com"
+
+begin
+ if (and (n_status[server], F_IOERR) == 0) {
+ call zawtks (n_kschan[server], status)
+ if (status == ERR)
+ call ki_error (server)
+ } else
+ status = ERR
+end
diff --git a/sys/ki/ksawrite.x b/sys/ki/ksawrite.x
new file mode 100644
index 00000000..20c815f5
--- /dev/null
+++ b/sys/ki/ksawrite.x
@@ -0,0 +1,21 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "ki.h"
+
+# KS_AWRITE -- Write to the kernel server device driver given the node
+# descriptor of a kernel server channel. If the error bit is set on the
+# node return error w/o doing any i/o, since the channel will have been closed.
+
+procedure ks_awrite (server, buf, nbytes)
+
+int server # node descriptor index of server
+char buf[ARB] # i/o buffer
+int nbytes # nbytes to write
+
+int and()
+include "kinode.com"
+
+begin
+ if (and (n_status[server], F_IOERR) == 0)
+ call zawrks (n_kschan[server], buf, nbytes, long(0))
+end
diff --git a/sys/ki/ktzcls.x b/sys/ki/ktzcls.x
new file mode 100644
index 00000000..826ad9f7
--- /dev/null
+++ b/sys/ki/ktzcls.x
@@ -0,0 +1,38 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KT_ZCLS -- Close a text device. We are called only if the device does not
+# reside on the local node.
+
+procedure kt_zcls (device, chan, status)
+
+int device # device driver code
+int chan # channel assigned device
+int status # receives ok|err
+
+int server
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+
+ # If we receive error on the KS channel when trying to close a file,
+ # it is most likely due to a previous i/o error on the channel. Do
+ # not return error here because we are probably being called during
+ # error recovery to free the logical channel, and if we return error
+ # the real error will be hidden.
+
+ if (ki_sendrcv (server, device, TX_CLS) == ERR)
+ status = OK
+ else
+ status = p_arg[1]
+
+ call mfree (k_bufp[chan], TY_STRUCT)
+ call ki_freechan (chan)
+end
diff --git a/sys/ki/ktzfls.x b/sys/ki/ktzfls.x
new file mode 100644
index 00000000..e22c1a98
--- /dev/null
+++ b/sys/ki/ktzfls.x
@@ -0,0 +1,33 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KT_ZFLS -- Flush output to a text device. We are called only if the device
+# does not reside on the local node.
+
+procedure kt_zfls (device, chan, status)
+
+int device # device driver code
+int chan # channel assigned device
+int status # receives nchars written or ERR
+
+int server
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ call ki_flushtx (device, chan, status)
+ if (status == ERR)
+ return
+
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+
+ if (ki_sendrcv (server, device, TX_FLS) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+end
diff --git a/sys/ki/ktzget.x b/sys/ki/ktzget.x
new file mode 100644
index 00000000..f45ae755
--- /dev/null
+++ b/sys/ki/ktzget.x
@@ -0,0 +1,106 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KT_ZGET -- Get all or part of a line of text from a text device. We are
+# called only if the device does not reside on the local node.
+
+procedure kt_zget (device, chan, obuf, maxch, status)
+
+int device # device driver code
+int chan # channel assigned device
+char obuf[maxch] # receives text
+int maxch # max chars to read
+int status # receives nchars read or ERR
+
+pointer bd, bp, ip, rp
+int server, nchars, nleft, reclen
+int ki_sendrcv()
+long ki_decode()
+include "kichan.com"
+include "kii.com"
+
+begin
+ bd = k_bufp[chan]
+
+ # Text file input is buffered; each input buffer returned by the kernel
+ # server may contain any number of lines of text. Each line of text
+ # is preceded by a record header containing the record length and seek
+ # offset of the line.
+
+ if (maxch == 1 || B_RP(bd) >= B_ITOP(bd)) {
+ # Refill buffer.
+
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+
+ # Read only one character if this is a raw mode read.
+ if (maxch == 1)
+ p_arg[2] = 1
+ else
+ p_arg[2] = SZ_TXBUF
+
+ if (ki_sendrcv (server, device, TX_GET) == ERR)
+ status = ERR
+ else if (p_arg[1] <= 0)
+ status = p_arg[1] # EOF or ERR
+ else {
+ nchars = p_arg[1]
+ bp = B_BUFPTR(bd)
+
+ # If the record is small it is returned in the string buffer,
+ # else it is returned as a second record. Each line is
+ # contained entirely in a single buffer.
+
+ if (nchars <= SZ_SBUF)
+ call amovc (p_sbuf, Memc[bp], nchars)
+ else {
+ call ks_aread (server, Memc[bp], nchars)
+ call ks_await (server, status)
+
+ if (status != nchars) {
+ call ki_error (server)
+ B_ITOP(bd) = bp
+ B_OTOP(bd) = bp
+ status = ERR
+ return
+ }
+
+ call chrupk (Memc[bp], 1, Memc[bp], 1, nchars)
+ }
+
+ B_RP(bd) = bp
+ B_ITOP(bd) = bp + nchars
+ B_OTOP(bd) = bp
+ B_CI(bd) = 0
+ }
+ }
+
+ # Return characters from the current record until it is exhausted.
+ # When the current record is empty, leave the record pointer pointing
+ # to the start of the next record and the character index pointing
+ # to the first char of that record.
+
+ rp = B_RP(bd)
+ ip = R_DATA(rp) + B_CI(bd)
+ reclen = ki_decode (R_RECLEN(rp), NCHARS_INT)
+ nleft = R_GETNCHARS (reclen) - B_CI(bd)
+
+ if (maxch >= nleft) {
+ # Return the remainder of the buffer.
+
+ call amovc (Memc[ip], obuf, nleft)
+ status = nleft
+ B_RP(bd) = B_RP(bd) + reclen
+ B_CI(bd) = 0
+
+ } else {
+ # Return a portion of the data remaining in the buffer.
+
+ call amovc (Memc[ip], obuf, maxch)
+ status = maxch
+ B_CI(bd) = B_CI(bd) + maxch
+ }
+end
diff --git a/sys/ki/ktznot.x b/sys/ki/ktznot.x
new file mode 100644
index 00000000..8185b734
--- /dev/null
+++ b/sys/ki/ktznot.x
@@ -0,0 +1,74 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KT_ZNOT -- Note the file position of a text device. We are called only if
+# the device does not reside on the local node.
+
+procedure kt_znot (device, chan, loffset)
+
+int device # device driver code
+int chan # channel assigned device
+long loffset # receives the file offset
+
+pointer bd, rp
+int server, status
+int ki_sendrcv()
+long ki_decode()
+include "kichan.com"
+include "kii.com"
+define physnote_ 91
+
+begin
+ bd = k_bufp[chan]
+
+ # The buffering of text file input and output complicates the seek and
+ # note functions. Our solution is [1] for an output file, flush the
+ # output and then call the kernel server to note the file position, and
+ # [2] for an input file, have the kernel server note the offset of each
+ # input line of text in the header area of each input record.
+
+ if (B_ITOP(bd) >= B_BUFPTR(bd)) {
+ # Input file.
+
+ rp = B_RP(bd)
+
+ # Check for end of input buffer.
+ if (rp >= B_ITOP(bd))
+ goto physnote_
+
+ # If already part way into line, return offset of the next line.
+ if (B_CI(bd) > 0) {
+ rp = rp + ki_decode (R_RECLEN(rp), NCHARS_INT)
+ if (rp >= B_ITOP(bd))
+ goto physnote_
+ }
+
+ # Decode seek offset from record header of next line to be
+ # read. The seek offset is encoded as a char sequence.
+
+ loffset = ki_decode (R_SEKOFF(rp), NCHARS_LONG)
+ return
+
+ } else {
+ # Output file.
+
+ call ki_flushtx (device, chan, status)
+ if (status == ERR)
+ return
+ }
+
+physnote_
+
+ # Physically call the kernel server to note the file offset.
+
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+
+ if (ki_sendrcv (server, device, TX_NOT) == ERR)
+ loffset = ERR
+ else
+ loffset = ki_decode (p_sbuf, NCHARS_LONG)
+end
diff --git a/sys/ki/ktzopn.x b/sys/ki/ktzopn.x
new file mode 100644
index 00000000..8a6c14b9
--- /dev/null
+++ b/sys/ki/ktzopn.x
@@ -0,0 +1,52 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include <mach.h>
+include "ki.h"
+
+# KT_ZOPN -- Open a text device. We are called only if the device does not
+# reside on the local node.
+
+procedure kt_zopn (device, osfn, mode, chan)
+
+int device # device driver code
+char osfn[ARB] # packed os filename
+int mode # access mode
+int chan # receives assigned channel
+
+pointer bd, bp
+int server
+int ki_connect(), ki_sendrcv(), ki_getchan(), kmalloc()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = ki_connect (osfn)
+ p_arg[2] = mode
+
+ if (ki_sendrcv (server, device, TX_OPN) == ERR)
+ chan = ERR
+ else if (p_arg[1] == ERR)
+ chan = ERR
+ else if (kmalloc (bd, LEN_TXBDES, TY_STRUCT) == ERR)
+ chan = ERR
+ else {
+ chan = ki_getchan (server, p_arg[1])
+ k_bufp[chan] = NULL
+
+ # Init the text buffer and buffer descriptor. Text i/o over the
+ # KI is buffered, greatly reducing the number of packets sent back
+ # and forth between nodes and likewise increasing the bandwidth.
+ # Buffering at the KI layer is necessary because FIO buffers only
+ # one line of text at a time, leaving blocking and deblocking of
+ # text lines to the kernel.
+
+ k_bufp[chan] = bd
+ bp = B_BUFPTR(bd)
+ B_RP(bd) = bp
+ B_CI(bd) = 0
+ B_ITOP(bd) = bp
+ B_OTOP(bd) = bp
+ B_BUFTOP(bd) = bp + SZ_TXBUF
+ }
+end
diff --git a/sys/ki/ktzput.x b/sys/ki/ktzput.x
new file mode 100644
index 00000000..f55380a9
--- /dev/null
+++ b/sys/ki/ktzput.x
@@ -0,0 +1,125 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KT_ZPUT -- Put a line of text to a text device. We are called only if the
+# device does not reside on the local node. Output is buffered for greater
+# bandwidth and efficiency.
+
+procedure kt_zput (device, chan, ibuf, nchars, status)
+
+int device # device driver code
+int chan # channel assigned device
+char ibuf[nchars] # receives text
+int nchars # nchars to write
+int status # receives nchars written or ERR
+
+pointer bd, ep
+include "kichan.com"
+
+begin
+ bd = k_bufp[chan]
+ ep = B_RP(bd) + nchars - 1
+
+ # If this is the first write into the buffer, OTOP will be set to
+ # the beginning of the buffer and we must reset it to the end.
+
+ if (ep >= B_OTOP(bd)) {
+ # Check whether there is room remaining in the buffer for the data.
+ # We do not break output lines across buffer boundaries.
+
+ if (ep >= B_BUFTOP(bd)) {
+ call ki_flushtx (device, chan, status)
+ if (status == ERR)
+ return
+
+ # Check for buffer too small to hold data record. This should
+ # not be possible if SZ_TXBUF is chosen large enough, because
+ # FIO will break records larger than the FIO buffer size.
+
+ if (nchars > SZ_TXBUF) {
+ status = ERR
+ return
+ }
+ }
+
+ B_OTOP(bd) = B_BUFTOP(bd)
+ }
+
+ # Append the text data to the output buffer.
+
+ call amovc (ibuf, Memc[B_RP(bd)], nchars)
+ B_RP(bd) = B_RP(bd) + nchars
+ status = nchars
+end
+
+
+# KI_FLUSHTX -- Flush any buffered output of a text file. Text output is
+# transmitted as a stream without reading the status back after each write.
+# If a write error occurs on the logical channel to the text file, the kernel
+# server will shut down entirely, causing a write error on the physical
+# channel to the kernel server. It is harmless if we are called when the
+# output buffer is empty or contains input data.
+
+procedure ki_flushtx (device, chan, status)
+
+int device # text file device code
+int chan # channel assigned device
+int status # receives nchars written or ERR
+
+pointer bd, bp
+int server, nchars
+int ki_send()
+include "kichan.com"
+include "kii.com"
+
+begin
+ bd = k_bufp[chan]
+ bp = B_BUFPTR(bd)
+
+ # OTOP will have been set to BUFTOP if the buffer was written into.
+ # RP may be greater than BUFPTR for input buffers, too. If there is
+ # nothing to flush return without taking any action and without
+ # changing any file pointers.
+
+ nchars = min (B_OTOP(bd), B_RP(bd)) - bp
+ if (nchars <= 0) {
+ status = 0
+ return
+ }
+
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+ p_arg[2] = nchars
+
+ # If the buffer is small enough it is sent in the string buffer,
+ # otherwise it is sent as a second record.
+
+ if (nchars <= SZ_SBUF) {
+ call amovc (Memc[bp], p_sbuf, nchars)
+ p_sbuflen = nchars
+ } else
+ p_sbuflen = 0
+
+ # Send packet.
+ if (ki_send (server, device, TX_PUT) == ERR)
+ status = ERR
+ else if (nchars > SZ_SBUF) {
+ # Send data record.
+
+ call chrpak (Memc[bp], 1, Memc[bp], 1, nchars)
+ call ks_awrite (server, Memc[bp], nchars)
+ call ks_await (server, status)
+
+ if (status != nchars)
+ status = ERR
+ }
+
+ # Mark the buffer empty.
+
+ B_RP(bd) = bp
+ B_ITOP(bd) = bp
+ B_OTOP(bd) = bp
+end
diff --git a/sys/ki/ktzsek.x b/sys/ki/ktzsek.x
new file mode 100644
index 00000000..f8b20829
--- /dev/null
+++ b/sys/ki/ktzsek.x
@@ -0,0 +1,50 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KT_ZSEK -- Seek on a text device. We are called only if the device does not
+# reside on the local node.
+
+procedure kt_zsek (device, chan, loffset, status)
+
+int device # device driver code
+int chan # channel assigned device
+long loffset # znottx offset to seek to
+int status # receives nchars written or ERR
+
+pointer bd
+int server
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ call ki_flushtx (device, chan, status)
+ if (status == ERR)
+ return
+
+ # Discard any cached input text to force a buffer refill at the new
+ # offset.
+
+ bd = k_bufp[chan]
+ B_RP(bd) = B_ITOP(bd)
+
+ # Transmit the seek request to the server.
+
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+
+ # The long integer seek offset is passed as an encoded char sequence
+ # rather than as an integer p_arg value to avoid possible loss of
+ # precision.
+
+ call ki_encode (loffset, p_sbuf, NCHARS_LONG)
+ p_sbuflen = NCHARS_LONG
+
+ if (ki_sendrcv (server, device, TX_SEK) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+end
diff --git a/sys/ki/ktzstt.x b/sys/ki/ktzstt.x
new file mode 100644
index 00000000..c7ca9463
--- /dev/null
+++ b/sys/ki/ktzstt.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KT_ZSTT -- Get file status on a text device. We are called only if the
+# device does not reside on the local node.
+
+procedure kt_zstt (device, chan, what, lvalue)
+
+int device # device driver code
+int chan # channel assigned device
+int what # file parameter to be returned
+long lvalue # receives the parameter value
+
+int server
+int ki_sendrcv()
+long ki_decode()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+ p_arg[2] = what
+
+ if (ki_sendrcv (server, device, TX_STT) == ERR)
+ lvalue = ERR
+ else
+ lvalue = ki_decode (p_sbuf, NCHARS_LONG)
+end
diff --git a/sys/ki/kzclmt.x b/sys/ki/kzclmt.x
new file mode 100644
index 00000000..6d6bbb80
--- /dev/null
+++ b/sys/ki/kzclmt.x
@@ -0,0 +1,45 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <fio.h>
+include "ki.h"
+
+# KZCLMT -- Close a magtape file.
+
+procedure kzclmt (chan, devpos, status)
+
+int chan #I channel to be closed
+int devpos[ARB] #O receives position information
+int status #O close status
+
+int server
+int ki_sendrcv()
+include "kichan.com"
+include "kii.com"
+
+begin
+ # Possible if an abort occurs during the open.
+ if (chan <= 0) {
+ status = OK
+ return
+ }
+
+ if (k_node[chan] == NULL)
+ call zzclmt (k_oschan[chan], devpos, status)
+ else {
+ server = k_node[chan]
+ p_arg[1] = k_oschan[chan]
+
+ if (ki_sendrcv (server, KI_ZFIOMT, MT_CL) == ERR)
+ status = ERR
+ else {
+ status = p_arg[1]
+ call amovi (p_arg[2], devpos, LEN_MTDEVPOS)
+ }
+
+ call mfree (k_bufp[chan], TY_INT)
+ }
+
+ call ki_freechan (chan)
+end
diff --git a/sys/ki/kzopmt.x b/sys/ki/kzopmt.x
new file mode 100644
index 00000000..859c4657
--- /dev/null
+++ b/sys/ki/kzopmt.x
@@ -0,0 +1,90 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <fio.h>
+include "ki.h"
+
+# KZOPMT -- Open a magtape file.
+
+procedure kzopmt (device, mode, devcap, devpos, newfile, chan)
+
+char device[ARB] #I logical device name
+int mode #I access mode
+char devcap[ARB] #I tapecap entry for device
+int devpos[ARB] #I tape position information
+int newfile #U receives new file number
+int chan #O channel assigned for reading filenames
+
+pointer sp, bp, bd
+int server, dv_len, dc_len, dc_off
+int ki_connect(), ki_send(), ki_receive(), ki_getchan()
+int kmalloc(), strlen()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = ki_connect (device)
+
+ # We must preallocate a channel descriptor in order for error
+ # recovery to work, if an abort occurs during the zzopmt.
+
+ chan = ki_getchan (server, chan)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zzopmt (p_sbuf, mode, devcap, devpos, newfile, k_oschan[chan])
+
+ } else {
+ call smark (sp)
+ call salloc (bp, SZ_COMMAND, TY_CHAR)
+
+ # Determine whether devcap string will fit in sbuf.
+ call strupk (devcap, Memc[bp], SZ_COMMAND)
+ dv_len = strlen (p_sbuf[p_arg[1]])
+ dc_len = strlen (Memc[bp])
+ if (p_arg[1] + dv_len+1 + dc_len > SZ_SBUF)
+ dc_off = 0
+ else {
+ dc_off = p_arg[1] + dv_len + 1
+ call strcpy (Memc[bp], p_sbuf[dc_off], ARB)
+ p_sbuflen = dc_off + dc_len
+ }
+
+ # Prepare the arguments.
+ p_arg[2] = mode
+ p_arg[3] = dc_off
+ p_arg[4] = dc_len
+ p_arg[5] = newfile
+ call amovi (devpos, p_arg[6], LEN_MTDEVPOS)
+
+ if (ki_send (server, KI_ZFIOMT, MT_OP) == ERR)
+ k_oschan[chan] = ERR
+ else if (dc_len > 0 && dc_off == 0) {
+ call ks_awrite (server, devcap, dc_len+1)
+ call ks_await (server, k_oschan[chan])
+ }
+
+ if (ki_receive (server, KI_ZFIOMT, MT_OP) == ERR)
+ k_oschan[chan] = ERR
+ else {
+ k_oschan[chan] = p_arg[1]
+ newfile = p_arg[2]
+ }
+
+ call sfree (sp)
+ }
+
+ if (k_oschan[chan] == ERR) {
+ call ki_freechan (chan)
+ chan = ERR
+ } else {
+ if (server != NULL) {
+ if (kmalloc (bd, LEN_MTDEVPOS, TY_INT) == ERR) {
+ call ki_freechan (chan)
+ chan = ERR
+ } else
+ k_bufp[chan] = bd
+ }
+ }
+end
diff --git a/sys/ki/kzrdmt.x b/sys/ki/kzrdmt.x
new file mode 100644
index 00000000..7fdaf517
--- /dev/null
+++ b/sys/ki/kzrdmt.x
@@ -0,0 +1,63 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <fio.h>
+include "ki.h"
+
+# KZRDMT -- Asynchronous read from a magtape file.
+
+procedure kzrdmt (chan, obuf, max_bytes, offset)
+
+int chan #I magtape channel
+char obuf[ARB] #O buffer to receive data
+int max_bytes #I max bytes to read
+long offset #I file offset
+
+pointer bd
+int server, status
+int ki_send(), ki_receive()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = k_node[chan]
+
+ if (server == NULL) {
+ call zzrdmt (k_oschan[chan], obuf, max_bytes, offset)
+ return
+ }
+
+ # Ignore zero reads and requests on a node closed by an error.
+ if (max_bytes <= 0) {
+ k_status[chan] = 0
+ return
+ }
+
+ # Send the request to initiate the read.
+ p_arg[1] = k_oschan[chan]
+ p_arg[2] = max_bytes
+ p_arg[3] = offset
+
+ if (ki_send (server, KI_ZFIOMT, MT_RD) == ERR) {
+ status = ERR
+ } else {
+ bd = k_bufp[chan]
+
+ # Wait for the ZAWT packet.
+ if (ki_receive (server, KI_ZFIOMT, MT_WT) == ERR)
+ status = ERR
+ else {
+ status = p_arg[1]
+ call amovi (p_arg[2], Memi[bd], LEN_MTDEVPOS)
+ }
+
+ # Read the data block (if any) directly into caller's buffer.
+ if (status > 0) {
+ call ks_aread (server, obuf, status)
+ call ks_await (server, status)
+ }
+ }
+
+ k_status[chan] = status
+end
diff --git a/sys/ki/kzrwmt.x b/sys/ki/kzrwmt.x
new file mode 100644
index 00000000..38ce6634
--- /dev/null
+++ b/sys/ki/kzrwmt.x
@@ -0,0 +1,63 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include <fio.h>
+include "ki.h"
+
+# KZRWMT -- Rewind a (nonopen) magtape drive.
+
+procedure kzrwmt (drive, devcap, status)
+
+char drive[ARB] #I packed name of drive to be rewound
+char devcap[ARB] #I packed tapecap entry for device
+int status #O receives status, ok|err
+
+pointer sp, bp
+int server, dv_len, dc_len, dc_off, nbytes
+int ki_connect(), ki_send(), ki_receive(), strlen()
+include "kii.com"
+
+begin
+ server = ki_connect (drive)
+
+ if (server == NULL) {
+ call strpak (p_sbuf[p_arg[1]], p_sbuf, SZ_SBUF)
+ call zzrwmt (p_sbuf, devcap, status)
+
+ } else {
+ call smark (sp)
+ call salloc (bp, SZ_COMMAND, TY_CHAR)
+
+ # Determine whether devcap string will fit in sbuf.
+ call strupk (devcap, Memc[bp], SZ_COMMAND)
+ dv_len = strlen (p_sbuf[p_arg[1]])
+ dc_len = strlen (Memc[bp])
+ if (dv_len+1 + dc_len > SZ_SBUF) {
+ dc_off = 0
+ nbytes = (dc_len + SZB_CHAR-1) / SZB_CHAR
+ } else {
+ dc_off = dv_len + 1
+ call strcpy (Memc[bp], p_sbuf[dc_off], ARB)
+ p_sbuflen = dc_off + dc_len
+ }
+
+ # Prepare the arguments.
+ p_arg[2] = dc_off
+ p_arg[3] = dc_len
+
+ if (ki_send (server, KI_ZFIOMT, MT_RW) == ERR)
+ status = ERR
+ else if (dc_len > 0 && dc_off == 0) {
+ call ks_awrite (server, devcap, nbytes)
+ call ks_await (server, status)
+ }
+
+ if (ki_receive (server, KI_ZFIOMT, MT_RW) == ERR)
+ status = ERR
+ else
+ status = p_arg[1]
+
+ call sfree (sp)
+ }
+end
diff --git a/sys/ki/kzstmt.x b/sys/ki/kzstmt.x
new file mode 100644
index 00000000..2aaa0f45
--- /dev/null
+++ b/sys/ki/kzstmt.x
@@ -0,0 +1,21 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include "ki.h"
+
+# KZSTMT -- Device status for a magtape device.
+
+procedure kzstmt (chan, what, lvalue)
+
+int chan #I active magtape channel
+int what #I device parameter
+long lvalue #O parameter value
+
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zzstmt (k_oschan[chan], what, lvalue)
+ else
+ call kb_zstt (KI_ZFIOMT, chan, what, lvalue)
+end
diff --git a/sys/ki/kzwrmt.x b/sys/ki/kzwrmt.x
new file mode 100644
index 00000000..74ae0dd9
--- /dev/null
+++ b/sys/ki/kzwrmt.x
@@ -0,0 +1,49 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <config.h>
+include "ki.h"
+
+# KZWRMT -- Asynchronous write to a magtape file.
+
+procedure kzwrmt (chan, buf, nbytes, offset)
+
+int chan #I magtape channel
+char buf[ARB] #I buffer containing data
+int nbytes #I nbytes to write
+long offset #I file offset
+
+int server
+int ki_send()
+include "kichan.com"
+include "kii.com"
+
+begin
+ server = k_node[chan]
+
+ if (server == NULL) {
+ call zzwrmt (k_oschan[chan], buf, nbytes, offset)
+ return
+ }
+
+ # Ignore zero writes and requests on a node closed by an error.
+ if (nbytes <= 0) {
+ k_status[chan] = 0
+ return
+ }
+
+ # Send the request followed by the data block. We do not read anything
+ # back from the remote server until ZAWT is called. Set k_status[chan]
+ # to WRITE_IN_PROGRESS to tell ZAWT that an await call is needed.
+
+ p_arg[1] = k_oschan[chan]
+ p_arg[2] = nbytes
+ p_arg[3] = offset
+
+ if (ki_send (server, KI_ZFIOMT, MT_WR) == ERR)
+ k_status[chan] = ERR
+ else {
+ call ks_awrite (server, buf, nbytes)
+ call ks_await (server, k_status[chan])
+ }
+end
diff --git a/sys/ki/kzwtmt.x b/sys/ki/kzwtmt.x
new file mode 100644
index 00000000..3358d83e
--- /dev/null
+++ b/sys/ki/kzwtmt.x
@@ -0,0 +1,26 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <config.h>
+include <fio.h>
+include "ki.h"
+
+# KZWTMT -- Wait for i/o to complete on a magtape channel.
+
+procedure kzwtmt (chan, devpos, status)
+
+int chan #I active magtape channel
+int devpos[ARB] #O device position structure
+int status #O receives nbytes transferred or ERR
+
+pointer bd
+include "kichan.com"
+
+begin
+ if (k_node[chan] == NULL)
+ call zzwtmt (k_oschan[chan], devpos, status)
+ else {
+ bd = k_bufp[chan]
+ status = k_status[chan]
+ call amovi (Memi[bd], devpos, LEN_MTDEVPOS)
+ }
+end
diff --git a/sys/ki/mkpkg b/sys/ki/mkpkg
new file mode 100644
index 00000000..65a0c895
--- /dev/null
+++ b/sys/ki/mkpkg
@@ -0,0 +1,107 @@
+# Update the KI kernel interface.
+
+$checkout libsys.a lib$
+$update libsys.a
+$checkin libsys.a lib$
+$exit
+
+update:
+ $call relink
+ $call install
+ ;
+
+relink:
+ $omake irafks.x\
+ ki.h kii.com <clset.h> <finfo.h> <fset.h> <knet.h> <mach.h>
+ $link irafks.o
+ ;
+
+install:
+ $move irafks.e bin$
+ ;
+
+libsys.a:
+ # Do not put irafks.x in this list.
+ kbzard.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kbzawr.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kbzawt.x ki.h kichan.com <config.h>
+ kbzcls.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kbzopn.x ki.h kii.com <mach.h>
+ kbzstt.x ki.h kichan.com kii.com kinode.com <config.h>\
+ <fio.h> <mach.h>
+ kclcpr.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kcldir.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kcldpr.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kdvall.x ki.h kii.com <mach.h>
+ kdvown.x ki.h kii.com <mach.h>
+ kfacss.x ki.h kii.com <mach.h>
+ kfaloc.x ki.h kii.com <mach.h>
+ kfchdr.x ki.h kii.com kinode.com <chars.h> <config.h> <mach.h>
+ kfdele.x ki.h kii.com <mach.h>
+ kfgcwd.x ki.h kii.com kinode.com <chars.h> <config.h> <mach.h>
+ kfinfo.x ki.h kii.com <finfo.h> <mach.h>
+ kfiobf.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kfiogd.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kfiolp.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kfiopl.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kfiopr.x ki.h kichan.com <config.h> <mach.h>
+ kfiosf.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kfiotx.x ki.h kichan.com kii.com <config.h> <fio.h> <mach.h>
+ kfioty.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kfmkcp.x ki.h kii.com <mach.h>
+ kfmkdr.x ki.h kii.com <mach.h>
+ kfpath.x ki.h kinode.com <chars.h>
+ kfprot.x ki.h kii.com <mach.h>
+ kfrnam.x ki.h kii.com <mach.h>
+ kfrmdr.x ki.h kii.com <mach.h>
+ kfsubd.x ki.h
+ kfutim.x ki.h kii.com <mach.h>
+ kfxdir.x ki.h kinode.com <chars.h>
+ kgfdir.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kiconnect.x ki.h kichan.com kii.com kinode.com <chars.h>\
+ <config.h> <mach.h>
+ kiencode.x
+ kienvreset.x ki.h kii.com kinode.com <config.h> <mach.h>
+ kierror.x kinode.com ki.h <config.h>
+ kiextnode.x ki.h kinode.com <chars.h>
+ kifchan.x kichan.com kinode.com ki.h <config.h>
+ kifmapfn.x ki.h kii.com <mach.h>
+ kifndnode.x kinode.com ki.h
+ kigchan.x kichan.com kinode.com ki.h <config.h>
+ kighost.x ki.h kinode.com <ctype.h>
+ kignode.x kinode.com <chars.h> <ctype.h> ki.h
+ kiinit.x ki.h kichan.com kinode.com <config.h>
+ kilnode.x kinode.com ki.h
+ kimapchan.x ki.h kichan.com kinode.com <config.h> <knet.h> <mach.h>
+ kimapname.x
+ kintpr.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kiopenks.x ki.h kii.com kinode.com <chars.h> <config.h> <mach.h>
+ kireceive.x ki.h kii.com kinode.com <ctype.h> <mach.h>
+ kisend.x ki.h kii.com <mach.h>
+ kisendrcv.x
+ kishownet.x ki.h kinode.com <config.h> <mach.h>
+ kixnode.x
+ kopcpr.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kopdir.x ki.h kichan.com kii.com <config.h> <diropen.h> <mach.h>
+ kopdpr.x ki.h kii.com <mach.h>
+ koscmd.x ki.h kii.com kinode.com <chars.h> <config.h>\
+ <ctype.h> <mach.h>
+ ksaread.x ki.h kinode.com
+ ksawait.x ki.h kinode.com
+ ksawrite.x ki.h kinode.com
+ ktzcls.x ki.h kichan.com kii.com <config.h> <mach.h>
+ ktzfls.x ki.h kichan.com kii.com <config.h> <mach.h>
+ ktzget.x ki.h kichan.com kii.com <config.h> <mach.h>
+ ktznot.x ki.h kichan.com kii.com <config.h> <mach.h>
+ ktzopn.x ki.h kichan.com kii.com <config.h> <mach.h>
+ ktzput.x ki.h kichan.com kii.com <config.h> <mach.h>
+ ktzsek.x ki.h kichan.com kii.com <config.h> <mach.h>
+ ktzstt.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kzclmt.x ki.h kichan.com kii.com <config.h> <fio.h> <mach.h>
+ kzopmt.x ki.h kichan.com kii.com <config.h> <fio.h> <mach.h>
+ kzrdmt.x ki.h kichan.com kii.com <config.h> <fio.h> <mach.h>
+ kzrwmt.x ki.h kii.com <config.h> <fio.h> <mach.h>
+ kzstmt.x ki.h kichan.com <config.h>
+ kzwrmt.x ki.h kichan.com kii.com <config.h> <mach.h>
+ kzwtmt.x ki.h kichan.com <config.h> <fio.h>
+ ;
diff --git a/sys/ki/zzdebug.x b/sys/ki/zzdebug.x
new file mode 100644
index 00000000..550fcc3f
--- /dev/null
+++ b/sys/ki/zzdebug.x
@@ -0,0 +1,120 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+task rexec = t_rexec,
+ rtype = t_rtype,
+ rread = t_rread,
+ encode = t_encode
+
+define SZ_BUF 4096
+
+
+# REXEC -- Execute a command on a remote node and print the resultant output on
+# the standard output. Used to test the kernel server driver.
+
+procedure t_rexec()
+
+char server[SZ_LINE]
+char buf[SZ_BUF]
+int chan, nbytes, status
+
+begin
+ call clgstr ("server", server, SZ_LINE)
+ call strpak (server, server, SZ_LINE)
+
+ call zopnks (server, READ_WRITE, chan)
+ if (chan == ERR)
+ call error (1, "cannot connect to remote server process")
+
+ repeat {
+ call zardks (chan, buf, SZ_BUF, 0)
+ call zawtks (chan, nbytes)
+
+ if (nbytes > 0) {
+ call chrupk (buf, 1, buf, 1, nbytes)
+ call write (STDOUT, buf, nbytes)
+ call flush (STDOUT)
+ }
+ } until (nbytes <= 0)
+
+ call zclsks (chan, status)
+ if (status == ERR)
+ call error (1, "error disconnecting server process")
+end
+
+
+# RTYPE -- Type a text file possibly resident on a remote node.
+
+procedure t_rtype()
+
+char fname[SZ_FNAME]
+char lbuf[SZ_LINE]
+int fd
+int open(), getline()
+
+begin
+ call clgstr ("file", fname, SZ_FNAME)
+ fd = open (fname, READ_ONLY, TEXT_FILE)
+
+ while (getline (fd, lbuf) != EOF) {
+ call putline (STDOUT, lbuf)
+ call flush (STDOUT)
+ }
+
+ call close (fd)
+end
+
+
+# RREAD -- Read a binary file.
+
+procedure t_rread()
+
+char fname[SZ_FNAME]
+char dbuf[SZ_BUF]
+int fd
+long nchars, totchars
+int open(), read()
+
+begin
+ call clgstr ("file", fname, SZ_FNAME)
+ fd = open (fname, READ_ONLY, BINARY_FILE)
+
+ totchars = 0
+
+ repeat {
+ nchars = read (fd, dbuf, SZ_BUF)
+ if (nchars > 0)
+ totchars = totchars + nchars
+ } until (nchars == EOF)
+
+ call close (fd)
+
+ call printf ("read %d chars\n")
+ call pargi (totchars)
+end
+
+
+# ENCODE -- Test the kiencode/decode routines.
+
+procedure t_encode()
+
+int v, ip
+char xnum[8]
+int ki_decode(), clgeti()
+
+begin
+ repeat {
+ v = clgeti ("value")
+ call ki_encode (v, xnum, 8)
+ call chrpak (xnum, 1, xnum, 1, 8)
+ call chrupk (xnum, 1, xnum, 1, 8)
+
+ call printf ("\t")
+ for (ip=1; ip <= 8; ip=ip+1) {
+ call printf ("%3d ")
+ call pargc (xnum[ip])
+ }
+
+ call printf (" --> %d\n")
+ call pargi (ki_decode (xnum, 8))
+ }
+end
diff --git a/sys/ki/zzrdks.c b/sys/ki/zzrdks.c
new file mode 100644
index 00000000..40229d5b
--- /dev/null
+++ b/sys/ki/zzrdks.c
@@ -0,0 +1,29 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+int spoolit = 0;
+int spoolfd = 0;
+
+/* Intercept KS intput and spool in a file for subsequent debugging.
+ * [MACHDEP]. This is a UNIX dependent debugging routine. To get rid of
+ * it, delete the file, edit the Makefile, and change the reference to
+ * zzrdks in irafks.x to zardks.
+ */
+zzrdks_ (chan, buf, maxb, off)
+int *chan;
+short *buf;
+int *maxb;
+int *off;
+{
+ int status;
+
+ zardks_ (chan, buf, maxb, off);
+
+ if (spoolit) {
+ if (spoolfd == 0)
+ spoolfd = creat ("/tmp/ks.in", 0644);
+ zawtks_ (chan, &status);
+ if (status > 0)
+ write (spoolfd, buf, status);
+ }
+}