diff options
author | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
---|---|---|
committer | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
commit | 40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch) | |
tree | 4464880c571602d54f6ae114729bf62a89518057 /unix/os/net/zfioks.c | |
download | iraf-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.c | 441 |
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; + } +} |