aboutsummaryrefslogtreecommitdiff
path: root/unix/os/net/zfioks.c
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /unix/os/net/zfioks.c
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'unix/os/net/zfioks.c')
-rw-r--r--unix/os/net/zfioks.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/unix/os/net/zfioks.c b/unix/os/net/zfioks.c
new file mode 100644
index 00000000..1db9cc1e
--- /dev/null
+++ b/unix/os/net/zfioks.c
@@ -0,0 +1,441 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <setjmp.h>
+
+#include "types.h"
+#include "in.h"
+
+#define import_kernel
+#define import_knames
+#define import_zfstat
+#define import_spp
+#include <iraf.h>
+
+/* ZFIOKS -- File i/o to a remote kernel server. This driver is the network
+ * interface for the kernel interface package (sys$ki). The KS driver is
+ * normally called directly by the KI routines, but is patterned after the
+ * regular FIO drivers hence may be connected to FIO to provide a network
+ * interface to the high level code.
+ *
+ * zopcks open kernel server on remote node
+ * zclcks close kernel server
+ * zardks read from the remote kernel server
+ * zawrks write to the remote kernel server
+ * zawtks wait for i/o
+ * zsttks get channel/device status
+ *
+ * The network interface used is an emulation of the Berkeley UNIX function
+ * REXEC on top of a standard TCP/IP interface.
+ */
+
+#define SZ_NAME 32 /* max size node, etc. name */
+#define SZ_CMD 128 /* max size rexec sh command */
+#define FNNODE_CHAR '!' /* node name delimiter */
+#define HOSTLOGIN "hostlogin" /* user host login file */
+#define IRAFHOSTS ".irafhosts" /* default host login file (dev$) */
+#define USER "<user>" /* symbol for user's login name */
+
+int ks_ionbytes[MAXOFILES]; /* nbytes read|written on channel */
+static jmp_buf jmpbuf;
+static int recursion = 0;
+
+
+/* ZOPNKS -- Open a connected subprocess on a remote node. Parse the "server"
+ * argument to obtain the node name and the command to be issued to connect the
+ * remote process. Call REXEC to exec the remote process and set up a socket
+ * to be used for CLIN, CLOUT to the remote process. The "server" string is
+ * implementation dependent and normally comes from the file "dev$hosts" on each
+ * node. This file is read by the high level code before we are called.
+ */
+ZOPNKS (server, mode, chan)
+PKCHAR *server; /* node name ! command */
+XINT *mode; /* access mode (not used) */
+XINT *chan; /* receives channel code (socket) */
+{
+ register char *ip;
+ char username[SZ_NAME+1], password[SZ_NAME+1];
+ char *host, *cmd;
+ int ipport;
+
+ /* Extract the host name and remote process spawn command from the
+ * server string, format "host!cmd", e.g., "2!/iraf/lib/irafks.e".
+ * If the server is "host", we are being called from a server process
+ * to set up communications with the host process. The UNIX rexec
+ * connects the host to the process standard input and output, hence
+ * if the server is "host" the channels are already active.
+ */
+ if (strcmp ((char *)server, "host") == 0) {
+ *chan = 0;
+ return;
+ }
+
+ host = (char *)server;
+ cmd = NULL;
+
+ for (ip = (char *)server; *ip != EOS; ip++)
+ if (*ip == FNNODE_CHAR) {
+ *ip = EOS;
+ cmd = ip + 1;
+ break;
+ }
+ if (cmd == NULL) {
+ *chan = ERR;
+ return;
+ }
+
+ /* Get login name and password and connect to the kernel server
+ * process. TCP_REXEC is a portable version of the Berkeley UNIX
+ * REXEC facility (see ./net).
+ */
+ if (ks_getlogin (host, username, password) == ERR)
+ *chan = ERR;
+ else {
+ ipport = htons (IPPORT_EXECSERVER);
+ *chan = tcp_rexec (&host, ipport, username, password, cmd, 0);
+ }
+
+ if (*chan > 0)
+ ks_ionbytes[*chan] = 0;
+}
+
+
+/* KS_GETLOGIN -- Get the user's login name and password, required for
+ * authentication on the remote machine. We could get these from the unix
+ * password file on the local machine, but there is no guarantee that the
+ * login name and password would be the same on a remote node as on the
+ * local machine. Instead we look in the user's unix login directory for
+ * the file ".irafhosts". If this file cannot be opened or if it does not
+ * contain an entry for the named node we use a default public login. The
+ * public login provides sufficient priviledge for most operations but will
+ * not provide write access to the user's files on the remote node.
+ */
+ks_getlogin (node, username, password)
+char *node; /* node we wish a login for */
+char *username; /* receives the login name */
+char *password; /* receives the login password */
+{
+ char fname[SZ_FNAME+1];
+ char uname[SZ_FNAME+1];
+
+ /* Get the user login name on the local node, used as the default
+ * login for remote nodes. [MACHDEP - edit for local system]
+ */
+ strcpy (uname, "USER");
+
+ /* Try to open the .irafhosts file in the user's login directory.
+ */
+ if (ku_mkfname ("home", "", IRAFHOSTS, fname, SZ_FNAME) != ERR)
+ if (ks_scanlogin (fname, node, uname, username, password) == OK)
+ return (OK);
+
+ /* Scan the dev$hostlogin file and return a default public login
+ * on the remote node.
+ */
+ if (ku_mkfname ("iraf", "dev", HOSTLOGIN, fname, SZ_FNAME) != ERR)
+ return (ks_scanlogin (fname, node, uname, username, password));
+
+ return (ERR);
+}
+
+
+/* KS_SCANLOGIN -- Open and scan a host login file, returning the login
+ * name and password to be used on the named node. The format of the table
+ * is a series of lines of the form
+ *
+ * alias1 alias2 ... aliasN : loginname password
+ *
+ * If the same login name and password are used on several nodes, a single
+ * entry may be given for all. If the alias "*" is encountered scanning stops
+ * and the next login name and password are used. The table file should of
+ * course be protected from reading except by the owner. If even this is
+ * considered too dangerous, the password "?" may be given in the table and a
+ * runtime query will result - this will fail if one is no longer logged in.
+ */
+ks_scanlogin (fname, node, uname, username, password)
+char *fname; /* table file */
+char *node; /* node name */
+char *uname; /* user login on local node */
+char *username; /* receives user login name */
+char *password; /* receives user password */
+{
+ char *ip;
+ char lbuf[SZ_LINE+1];
+ char wbuf[SZ_NAME+1];
+ int fp;
+ int foundit;
+ char *ku_fgets();
+
+ foundit = 0;
+ if ((fp = ku_fopen (fname, "r")) == ERR)
+ return (ERR);
+
+ /* Scan file for line containing node name.
+ */
+ while (!foundit && ku_fgets (lbuf, SZ_LINE, fp) != NULL) {
+ /* Skip blank lines and comment lines */
+ for (ip=lbuf; *ip == ' ' || *ip == '\t'; ip++)
+ ;
+ if (*ip == '#' || *ip == EOS)
+ continue;
+
+ /* Scan list of aliases */
+ while (ks_getword (&ip, wbuf) > 0) {
+ if (strcmp (wbuf, ":") == 0) {
+ break;
+ } else if (strcmp(wbuf,"*")==0 || strcmp(wbuf,node)==0) {
+ foundit++;
+ break;
+ }
+ }
+ }
+
+ ku_fclose (fp);
+ if (!foundit)
+ return (ERR);
+
+ /* Skip to end of alias list. */
+ while (ks_getword (&ip, wbuf) > 0) {
+ if (strcmp (wbuf, ":") == 0) {
+ /* Return login name and password.
+ */
+
+ /* If the login name is given as the USER string, use the
+ * login name on the local node. If the login name is given
+ * as "?", query the user for the actual login name.
+ */
+ if (ks_getword (&ip, username) <= 0)
+ return (ERR);
+ if (strcmp (username, USER) == 0)
+ strcpy (username, uname);
+ else if (strcmp (username, "?") == 0) {
+ char prompt[80];
+
+ sprintf (prompt, "Login name (%s@%s): ", username, node);
+ if (ku_gpasswd (prompt, username, SZ_NAME) == ERR)
+ return (ERR);
+ }
+
+ /* If the password is given as "?", query the user for
+ * the actual password.
+ */
+ if (ks_getword (&ip, password) <= 0)
+ return (ERR);
+ if (strcmp (password, "?") == 0) {
+ char prompt[80];
+
+ sprintf (prompt, "Password (%s@%s): ", username, node);
+ if (ku_gpasswd (prompt, password, SZ_NAME) == ERR)
+ return (ERR);
+ }
+
+ return (OK); /* SUCCESS */
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* KS_GETWORD -- Get the next whitespace or : delimited word from the
+ * input string.
+ */
+ks_getword (ip, obuf)
+char **ip; /* pointer into input buffer */
+char *obuf; /* receives name */
+{
+ register char *cp, *op;
+ register int n;
+
+ for (cp = *ip; isspace(*cp); cp++)
+ ;
+
+ op = obuf;
+ n = 0;
+
+ if (*cp == ':' || *cp == '*' || *cp == '?') {
+ *op++ = *cp++;
+ n++;
+ } else {
+ while (*cp && !isspace(*cp) && !(*cp==':' || *cp=='*' || *cp=='?'))
+ if (n++ >= SZ_NAME)
+ return (ERR);
+ else
+ *op++ = *cp++;
+ }
+
+ *op = EOS;
+ *ip = cp;
+
+ return (n);
+}
+
+
+/* ZCLSKS -- Close a kernel server connection.
+ */
+ZCLSKS (chan, status)
+XINT *chan; /* socket to kernel server */
+XINT *status; /* receives close status */
+{
+ *status = tcp_close (*chan);
+}
+
+
+/* ZARDKS -- Read from the kernel server channel. No attempt is made to
+ * impose a record structure upon the channel, as is the case with IPC.
+ * In UNIX the channel is stream oriented and it is up to the caller to
+ * unblock records from the input stream. Data blocks are assumed to be
+ * preceded by headers telling how much data to read, hence we read from
+ * the channel until the specified number of bytes have been read or ERR
+ * or EOF is seen on the stream.
+ */
+ZARDKS (chan, buf, totbytes, loffset)
+XINT *chan; /* kernel server channel (socket) */
+XCHAR *buf; /* output buffer */
+XINT *totbytes; /* total number of bytes to read */
+XLONG *loffset; /* not used */
+{
+ register char *op;
+ register int fd, nbytes;
+ int (*sigint)(), (*sigterm)();
+ int status;
+ extern pr_onsig();
+
+ fd = *chan;
+ op = (char *)buf;
+ ks_ionbytes[fd] = nbytes = *totbytes;
+
+ /* Now read exactly nbytes of data from channel into user buffer.
+ * Return actual byte count if EOF is seen. If ERR is seen return
+ * ERR. If necessary multiple read requests are issued to read the
+ * entire record. Reads are interruptable but the interrupt is caught
+ * and returned as a read error on the server channel.
+ */
+ sigint = signal (SIGINT, pr_onsig);
+ sigterm = signal (SIGTERM, pr_onsig);
+
+ while (nbytes > 0) {
+ if (setjmp (jmpbuf) == 0)
+ status = tcp_read (fd, op, nbytes);
+ else
+ status = ERR;
+
+ switch (status) {
+ case 0:
+ ks_ionbytes[fd] -= nbytes;
+ signal (SIGINT, sigint);
+ signal (SIGTERM, sigterm);
+ return;
+ case ERR:
+ ks_ionbytes[fd] = ERR;
+ signal (SIGINT, sigint);
+ signal (SIGTERM, sigterm);
+ return;
+ default:
+ nbytes -= status;
+ op += status;
+ break;
+ }
+ }
+
+ signal (SIGINT, sigint);
+ signal (SIGTERM, sigterm);
+}
+
+
+/* ZAWRKS -- Write to a kernel server channel.
+ */
+ZAWRKS (chan, buf, totbytes, loffset)
+XINT *chan; /* kernel server channel (socket) */
+XCHAR *buf; /* output buffer */
+XINT *totbytes; /* number of bytes to write */
+XLONG *loffset; /* not used */
+{
+ register int fd, ofd, nbytes;
+ int (*sigint)(), (*sigterm)(), (*sigpipe)();
+ extern pr_onsig();
+
+ /* If chan=0 (the process standard input) then we really want to
+ * write to channel 1, the standard output.
+ */
+ if ((ofd = fd = *chan) == 0)
+ ofd = 1;
+
+ ks_ionbytes[fd] = nbytes = *totbytes;
+
+ /* Write exactly nbytes of data to the channel from user buffer to
+ * the channel. Block interrupt during the write to avoid corrupting
+ * the data stream protocol if the user interrupts the client task.
+ * Trap SIGPIPE and return it as a write error on the channel instead.
+ * Likewise, turn an interrupt into a write error on the channel.
+ */
+ sigint = signal (SIGINT, pr_onsig);
+ sigterm = signal (SIGTERM, pr_onsig);
+ sigpipe = signal (SIGPIPE, pr_onsig);
+ recursion = 0;
+
+ if (setjmp (jmpbuf) == 0)
+ ks_ionbytes[fd] = tcp_write (ofd, (char *)buf, nbytes);
+ else
+ ks_ionbytes[fd] = ERR;
+
+ signal (SIGINT, sigint);
+ signal (SIGTERM, sigterm);
+ signal (SIGPIPE, sigpipe);
+}
+
+
+/* PR_ONSIG -- Catch a signal and make it look like a write error on the
+ * server i/o channel.
+ */
+pr_onsig (sig, code, scp)
+int sig; /* signal which was trapped */
+int code; /* subsignal code (vax) */
+struct sigcontext *scp; /* not used */
+{
+ if (sig == SIGPIPE && recursion++ == 0)
+ ku_error ("kernel server process has died");
+
+ longjmp (jmpbuf, sig);
+}
+
+
+/* ZAWTKS -- Wait for i/o to a KS channel. Since UNIX i/o is not asynchronous
+ * we do not really wait, rather we return the status value (byte count) from
+ * the last read or write to the channel.
+ */
+ZAWTKS (chan, status)
+XINT *chan;
+XINT *status;
+{
+ if ((*status = ks_ionbytes[*chan]) == ERR)
+ *status = XERR;
+}
+
+
+/* ZSTTKS -- Get binary file status for an KS channel. A KS channel is a
+ * streaming binary file.
+ */
+ZSTTKS (chan, param, lvalue)
+XINT *chan; /* not used; all KS channels have same status */
+XINT *param;
+XLONG *lvalue;
+{
+ switch (*param) {
+ case FSTT_BLKSIZE:
+ case FSTT_FILSIZE:
+ *lvalue = 0;
+ break;
+ case FSTT_OPTBUFSIZE:
+ *lvalue = KS_OPTBUFSIZE;
+ break;
+ case FSTT_MAXBUFSIZE:
+ *lvalue = KS_MAXBUFSIZE;
+ break;
+ default:
+ *lvalue = XERR;
+ }
+}