diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /sys/ki | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'sys/ki')
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); + } +} |