1
0
Files
irix-657m-src/eoe/cmd/bru/sys3.c
2022-09-29 17:59:04 +03:00

985 lines
18 KiB
C

/*
* This file contains intersystem compatibility routines derived from
* various public domain sources. This file is not subject to any of
* the licensing or distribution restrictions applicable to the rest
* of the bru source code. It is provided to improved transportability
* of bru source code between various flavors of unix.
*
* NOTE: The remote tape drive access routines are derived from a
* public domain version of the remote tape library originally
* produced at Georgia Tech. They are provided for convenience
* in using the bru source code on systems where the library has
* not been installed.
*
* They have been reformatted to fit in with the style in the
* rest of the bru source code but other than that are essentially
* unchanged.
*
* Fred Fish 28-Oct-85
*
*/
#include "autoconfig.h"
#if RMT
#include "typedefs.h"
#if (unix || xenix)
# if BSD
# include <sys/file.h> /* BSD DEPENDANT!!! */
# else
# include <fcntl.h> /* use this one for S5 with remote stuff */
# endif
# include <signal.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
#else
# include "sys.h"
#endif
#ifndef EOPNOTSUPP
#define EOPNOTSUPP EINVAL
#endif
#if BSD
extern int errno; /* Not in 4.2's <errno.h> */
#define strchr index
typedef int NBYTETYPE; /* Funny things, system calls... */
typedef char *IOCTL3;
extern int perror (), _exit ();
#else
# ifdef sgi
typedef char *IOCTL3;
# else
typedef int IOCTL3;
# endif
typedef unsigned int NBYTETYPE;
extern VOID perror (), _exit ();
#endif
/*
* If ioctl calls are supported on remote device then define
* RMTIOCTL.
*/
#if BSD || sgi
#define RMTIOCTL
#ifndef sgi
extern char *sprintf ();
#endif
#endif
#ifdef RMTIOCTL
#include <sys/ioctl.h>
#include <sys/mtio.h>
#endif
/*
* Note that local vs remote file descriptors are distinguished
* by adding a bias to the remote descriptors. This is a quick
* and dirty trick that may not be portable to some systems.
*/
#define REM_BIAS 128
/*
* BUFMAGIC --- Magic buffer size
* MAXUNIT --- Maximum number of remote tape file units
*/
#define BUFMAGIC 64
#define MAXUNIT 4
/*
* Useful macros.
*
* READ --- Return the number of the read side file descriptor
* WRITE --- Return the number of the write side file descriptor
*/
#ifdef sgi
# define READ(fd) fd
# define WRITE(fd) fd
#else
#define READ(fd) (_rmt_Ctp[fd][0])
#define WRITE(fd) (_rmt_Ptc[fd][1])
static int _rmt_Ctp[MAXUNIT][2] = {
-1, -1, -1, -1, -1, -1, -1, -1
};
static int _rmt_Ptc[MAXUNIT][2] = {
-1, -1, -1, -1, -1, -1, -1, -1
};
#endif
/*
* Isrmt. Let a programmer know he has a remote device.
*/
int isrmt (fd)
int fd;
{
return (fd & REM_BIAS);
}
/*
* abort --- close off a remote tape connection
*/
VOID _rmt_abort (fildes)
int fildes;
{
(VOID) close (READ (fildes));
(VOID) close (WRITE (fildes));
READ (fildes) = -1;
WRITE (fildes) = -1;
}
/*
* Test pathname for specified access. Looks just like access(2)
* to caller.
*/
int rmtaccess (path, amode)
char *path;
int amode;
{
if (_rmt_dev (path)) {
return (0); /* Let /etc/rmt find out */
} else {
return (access (path, amode));
}
}
/*
* Close a file. Looks just like close(2) to caller.
*/
int rmtclose (fildes)
int fildes;
{
if (isrmt (fildes)) {
return (_rmt_close (fildes & ~REM_BIAS));
} else {
return (close (fildes));
}
}
/*
* _rmt_close --- close a remote magtape unit and shut down
*/
static int _rmt_close (fildes)
int fildes;
{
int rc;
if (_rmt_command (fildes, "C\n") != -1) {
rc = _rmt_status (fildes);
_rmt_abort (fildes);
return (rc);
}
return (-1);
}
/*
* _rmt_command --- attempt to perform a remote tape command
*/
int _rmt_command (fildes, buf)
int fildes;
char *buf;
{
register int blen;
SIGTYPE pstat;
int err;
/*
* save current pipe status and try to make the request
*/
blen = strlen (buf);
pstat = signal (SIGPIPE, SIG_IGN);
writeagain:
if ((err = write (WRITE (fildes), buf, (NBYTETYPE) blen)) == blen) {
(VOID) signal (SIGPIPE, pstat);
return (0);
}
if (err == -1 && errno == EINTR)
goto writeagain;
/*
* something went wrong. close down and go home
*/
(VOID) signal (SIGPIPE, pstat);
_rmt_abort (fildes);
errno = EIO;
return (-1);
}
/*
* Create a file from scratch. Looks just like creat(2) to the caller.
*/
int rmtcreat (path, mode)
char *path;
int mode;
{
if (_rmt_dev (path)) {
return (rmtopen (path, 1 | O_CREAT, mode));
} else {
return (creat (path, mode));
}
}
/*
* Test pathname to see if it is local or remote. A remote device
* is any string that contains ":/dev/". Returns 1 if remote,
* 0 otherwise.
*/
int _rmt_dev (path)
register char *path;
{
extern char *strchr ();
if ((path = strchr (path, ':')) != (char *) 0) {
if (strncmp (path + 1, "/dev/", 5) == 0) {
return (1);
}
}
return (0);
}
/*
* Duplicate an open file descriptor. Looks just like dup(2)
* to caller.
*/
int rmtdup (fildes)
int fildes;
{
if (isrmt (fildes)) {
errno = EOPNOTSUPP;
return (-1); /* For now (fnf) */
} else {
return (dup (fildes));
}
}
/*
* Rmtfcntl. Do a remote fcntl operation.
*/
#ifdef DEADCODE
int rmtfcntl (fd, cmd, arg)
int fd;
int cmd;
int arg;
{
if (isrmt (fd)) {
errno = EOPNOTSUPP;
return (-1);
} else {
return (fcntl (fd, cmd, arg));
}
}
#endif /* DEADCODE */
/*
* Get file status. Looks just like fstat(2) to caller.
*/
#if !HAVE_SEEKDIR
int rmtfstat (fildes, buf)
int fildes;
struct stat64 *buf;
{
if (isrmt (fildes)) {
errno = EOPNOTSUPP;
return (-1); /* For now (fnf) */
} else {
return (fstat64 (fildes, buf));
}
}
#endif /* !HAVE_SEEKDIR */
/*
* Do ioctl on file. Looks just like ioctl(2) to caller.
*/
int rmtioctl (fildes, request, arg)
int fildes;
int request;
IOCTL3 arg;
{
if (isrmt (fildes)) {
#ifdef RMTIOCTL
return (_rmt_ioctl (fildes, request, arg));
#else
errno = EOPNOTSUPP;
return (-1); /* For now (fnf) */
#endif
} else {
return (ioctl (fildes, request, arg));
}
}
/*
* _rmt_ioctl --- perform raw tape operations remotely
*/
#ifdef RMTIOCTL
static _rmt_ioctl (fildes, op, arg)
int fildes;
int op;
IOCTL3 arg;
{
char c;
int rc;
int cnt;
char buffer[BUFMAGIC];
/*
* MTIOCOP is the easy one. nothing is transfered in binary
*/
if (op == MTIOCTOP) {
(VOID) sprintf (buffer, "I%d\n%d\n", ((struct mtop *) arg) -> mt_op,
((struct mtop *) arg) -> mt_count);
if (_rmt_command (fildes, buffer) == -1) {
return (-1);
}
return (_rmt_status (fildes));
}
/*
* we can only handle 2 ops, if not the other one, punt
*/
if (op != MTIOCGET) {
errno = EINVAL;
return (-1);
}
/*
* grab the status and read it directly into the structure
* this assumes that the status buffer is (hopefully) not
* padded and that 2 shorts fit in a long without any word
* alignment problems, ie - the whole struct is contiguous
* NOTE - this is probably NOT a good assumption.
*/
if (_rmt_command (fildes, "S\n") == -1 || (rc = _rmt_status (fildes)) == -1)
return (-1);
for (; rc > 0; rc -= cnt, arg += cnt) {
cnt = read (READ (fildes), arg, rc);
if (cnt == -1 && errno == EINTR) {
cnt = 0;
continue;
}
if (cnt <= 0) {
_rmt_abort (fildes);
errno = EIO;
return (-1);
}
}
/*
* now we check for byte position. mt_type is a small integer field
* (normally) so we will check its magnitude. if it is larger than
* 256, we will assume that the bytes are swapped and go through
* and reverse all the bytes
*/
if (((struct mtget *) arg) -> mt_type < 256) {
return (0);
}
for (cnt = 0; cnt < rc; cnt += 2) {
c = arg[cnt];
arg[cnt] = arg[cnt + 1];
arg[cnt + 1] = c;
}
return (0);
}
#endif /* RMTIOCTL */
/*
* Rmtisaatty. Do the isatty function.
*/
#ifdef DEADCODE
int rmtisatty (fd)
int fd;
{
if (isrmt (fd)) {
return (0);
} else {
return (isatty (fd));
}
}
#endif /* DEADCODE */
/*
* _rmt_lseek --- perform an imitation lseek operation remotely
*/
static long _rmt_lseek (fildes, offset, whence)
int fildes;
long offset;
int whence;
{
char buffer[BUFMAGIC];
(VOID) sprintf (buffer, "L%d\n%d\n", offset, whence);
if (_rmt_command (fildes, buffer) == -1) {
return (-1);
}
return (_rmt_status (fildes));
}
/*
* Perform lseek on file. Looks just like lseek(2) to caller.
*/
long rmtlseek (fildes, offset, whence)
int fildes;
long offset;
int whence;
{
extern long lseek ();
if (isrmt (fildes)) {
return (_rmt_lseek (fildes & ~REM_BIAS, offset, whence));
} else {
return (lseek (fildes, offset, whence));
}
}
/*
* Get file status, even if symlink. Looks just like lstat(2) to caller.
*/
#if HAVE_SYMLINKS
/*VARARGS1*/ /* Funny stuff because of "#define stat rmtstat" in rmt.h */
int rmtlstat (path, buf)
char *path;
struct stat64 *buf;
{
if (_rmt_dev (path)) {
errno = EOPNOTSUPP;
return (-1); /* For now (fnf) */
} else {
return (lstat64 (path, buf));
}
}
#endif
/*
* Open a local or remote file. Looks just like open(2) to
* caller.
*/
int rmtopen (path, oflag, mode)
char *path;
int oflag;
int mode;
{
if (_rmt_dev (path)) {
return (_rmt_open (path, oflag, mode) | REM_BIAS);
} else {
return (open (path, oflag, mode));
}
}
/*
* _rmt_open --- open a magtape device on system specified, as given user
*
* file name has the form system[.user]:/dev/????
*/
#define MAXHOSTLEN 257 /* BSD allows very long host names... */
/*ARGSUSED*/ /* Turn off lint checking for unused args in next func */
static int _rmt_open (path, oflag, mode)
char *path;
int oflag;
int mode;
{
int i;
int rc;
char buffer[BUFMAGIC];
char system[MAXHOSTLEN];
char device[BUFMAGIC];
char login[BUFMAGIC];
char *sys;
char *dev;
char *user;
sys = system;
dev = device;
user = login;
#ifndef sgi
/*
* first, find an open pair of file descriptors
*/
for (i = 0; i < MAXUNIT; i++) {
if (READ (i) == -1 && WRITE (i) == -1) {
break;
}
}
if (i == MAXUNIT) {
errno = EMFILE;
return (-1);
}
/*
* pull apart system and device, and optional user
* don't munge original string
*/
while (*path != '.' && *path != ':') {
*sys++ = *path++;
}
*sys = '\0';
path++;
if (*(path - 1) == '.') {
while (*path != ':') {
*user++ = *path++;
}
*user = '\0';
path++;
} else {
*user = '\0';
}
#else
{
char *s;
char *strchr();
*user = '\0';
if ((s = strchr(path, ':')) == 0)
*sys = '\0';
else {
char *t;
char *u;
*s = '\0';
if ((t = strchr(path, '.')) == 0) {
if ((u = strchr(path, '@')) == 0) {
strcpy(sys, path);
*user = '\0';
}
else {
*u = '\0';
strcpy(sys, u+1);
strcpy(user, path);
*u = '@';
}
}
else {
*t = '\0';
strcpy(sys, path);
strcpy(user, t+1);
*t = '.';
}
*s = ':';
path = s+1;
}
}
#endif
while (*path) {
*dev++ = *path++;
}
*dev = '\0';
#ifdef sgi
/*
* Blow off this mess if we've got inetd support locally.
* The descriptor returned is good for both reading and
* writing.
*/
if (login[0] != '\0') {
if ((i = contact(system, login, "/etc/rmt")) == -1) {
errno = EPERM;
return(-1);
}
}
else {
if ((i = contact(system, "guest", "/etc/rmt")) == -1) {
errno = EPERM;
return(-1);
}
}
#else
/*
* setup the pipes for the 'rsh' command and fork
*/
if (pipe (_rmt_Ptc[i]) == -1 || pipe (_rmt_Ctp[i]) == -1) {
return (-1);
}
if ((rc = fork ()) == -1) {
return (-1);
}
if (rc == 0) {
(VOID) close (0);
(VOID) dup (_rmt_Ptc[i][0]);
(VOID) close (_rmt_Ptc[i][0]);
(VOID) close (_rmt_Ptc[i][1]);
(VOID) close (1);
(VOID) dup (_rmt_Ctp[i][1]);
(VOID) close (_rmt_Ctp[i][0]);
(VOID) close (_rmt_Ctp[i][1]);
if (login) {
(VOID) execl ("/usr/ucb/rsh", "rsh", system, "-l", login,
"/etc/rmt", (char *) 0);
(VOID) execl ("/usr/bsd/rsh", "rsh", system, "-l", login,
"/etc/rmt", (char *) 0);
(VOID) execl ("/usr/bin/remsh", "remsh", system, "-l", login,
"/etc/rmt", (char *) 0);
(VOID) execl ("/bin/remsh", "remsh", system, "-l", login,
"/etc/rmt", (char *) 0);
(VOID) execl ("/bin/rsh", "rsh", system, "-l", login,
"/etc/rmt", (char *) 0);
} else {
(VOID) execl ("/usr/ucb/rsh", "rsh", system, "/etc/rmt",
(char *) 0);
(VOID) execl ("/usr/bsd/rsh", "rsh", system, "/etc/rmt",
(char *) 0);
(VOID) execl ("/usr/bin/remsh", "remsh", system, "/etc/rmt",
(char *) 0);
(VOID) execl ("/bin/remsh", "remsh", system, "/etc/rmt",
(char *) 0);
(VOID) execl ("/bin/rsh", "rsh", system, "/etc/rmt",
(char *) 0);
}
/*
* bad problems if we get here
*/
(VOID) perror ("can't find remote shell program");
(VOID) _exit (1);
}
(VOID) close (_rmt_Ptc[i][0]);
(VOID) close (_rmt_Ctp[i][1]);
#endif
/*
* now attempt to open the tape device
*/
(VOID) sprintf (buffer, "O%s\n%d\n", device, oflag);
if (_rmt_command (i, buffer) == -1 || _rmt_status (i) == -1) {
return (-1);
}
return (i);
}
#ifdef sgi
# include <stdio.h>
# include <bsd/netdb.h>
contact(node, user, cmd)
char *node;
char *user;
char *cmd;
{
struct servent *seb;
int fd;
char nbuf[128];
char *nnbuf;
void (*func)();
func = signal(SIGINT, SIG_DFL);
if ((seb = getservbyname("exec", "tcp")) == 0) {
fprintf(stderr, "Unable to contact name server demon\n");
signal(SIGINT, func);
return(-1);
}
strcpy(nbuf, node);
nnbuf = nbuf;
if ((fd = rexec(&nnbuf, seb->s_port, user, "", cmd, 0)) == -1) {
fprintf(stderr, "Unable to invoke remote demon at %s\n",
node);
signal(SIGINT, func);
return(-1);
}
signal(SIGINT, func);
return(fd);
}
#endif
/*
* Read from stream. Looks just like read(2) to caller.
*/
int rmtread (fildes, buf, nbyte)
int fildes;
char *buf;
unsigned int nbyte;
{
if (isrmt (fildes)) {
#ifdef sgi
int cnt;
unsigned int i;
i = 0;
while (i < nbyte) {
if ((cnt = _rmt_read (fildes & ~REM_BIAS, &buf[i], nbyte - i)) <= 0)
if (cnt == 0)
return (i);
else if (errno != EINTR)
return(-1);
else
continue;
i += cnt;
}
return (nbyte);
#else
return (_rmt_read (fildes & ~REM_BIAS, buf, nbyte));
#endif
} else {
return (read (fildes, buf, (NBYTETYPE) nbyte));
}
}
/*
* _rmt_read --- read a buffer from a remote tape
*/
static int _rmt_read (fildes, buf, nbyte)
int fildes;
char *buf;
unsigned int nbyte;
{
int rc;
int i;
register int bytesread;
char buffer[BUFMAGIC];
(VOID) sprintf (buffer, "R%d\n", nbyte);
if (_rmt_command (fildes, buffer) == -1 || (rc = _rmt_status (fildes)) == -1)
return (-1);
for (i = 0; i < rc; i += bytesread, buf += bytesread) {
bytesread = read (READ (fildes), buf, (NBYTETYPE) rc);
if (bytesread == -1 && errno == EINTR) {
bytesread = 0;
continue;
}
if (bytesread <= 0) {
_rmt_abort (fildes);
errno = EIO;
return (-1);
}
}
return (rc);
}
/*
* Get file status. Looks just like stat(2) to caller.
*/
#if !BSD4_2 /* Under BSD4_2 we use rmtlstat instead */
int rmtstat (path, buf)
char *path;
struct stat64 *buf;
{
extern int stat64 ();
if (_rmt_dev (path)) {
errno = EOPNOTSUPP;
return (-1); /* For now (fnf) */
} else {
return (stat64 (path, buf));
}
}
#endif /* Not BSD4_2 */
/*
* _rmt_status --- retrieve the status from the pipe
*/
int _rmt_status (fildes)
int fildes;
{
int i;
char c;
int err;
char *cp;
char buffer[BUFMAGIC];
/*
* read the reply command line
*/
for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++) {
readagain:
if ((err = read (READ (fildes), cp, 1)) != 1) {
if (err == -1 && errno == EINTR)
goto readagain;
_rmt_abort (fildes);
errno = EIO;
return (-1);
}
if (*cp == '\n') {
*cp = 0;
break;
}
}
if (i == BUFMAGIC) {
_rmt_abort (fildes);
errno = EIO;
return (-1);
}
/*
* check the return status
*/
for (cp = buffer; *cp; cp++) {
if (*cp != ' ') {
break;
}
}
if (*cp == 'E' || *cp == 'F') {
errno = atoi (cp + 1);
scanagain:
while ((err = read (READ (fildes), &c, 1)) == 1) {
if (c == '\n') {
break;
}
}
if (err == -1)
if (errno == EINTR)
goto scanagain;
else {
_rmt_abort (fildes);
return(-1);
}
if (*cp == 'F') {
_rmt_abort (fildes);
}
return (-1);
}
/*
* check for mis-synced pipes
*/
if (*cp != 'A') {
_rmt_abort (fildes);
errno = EIO;
return (-1);
}
return (atoi (cp + 1));
}
/*
* Write to stream. Looks just like write(2) to caller.
*/
int rmtwrite (fildes, buf, nbyte)
int fildes;
char *buf;
unsigned int nbyte;
{
if (isrmt (fildes)) {
#ifdef notdef
int cnt;
unsigned int i;
i = 0;
while (i < nbyte) {
if ((cnt = _rmt_write (fildes &~REM_BIAS, &buf[i], nbyte - i)) <= 0)
if (cnt == 0)
return(i);
else if (errno != EINTR)
return(-1);
else
continue;
i += cnt;
}
return (nbyte);
#else
return (_rmt_write (fildes & ~REM_BIAS, buf, nbyte));
#endif
} else {
return (write (fildes, buf, (NBYTETYPE) nbyte));
}
}
/*
* _rmt_write --- write a buffer to the remote tape
*/
static int _rmt_write (fildes, buf, nbyte)
int fildes;
char *buf;
unsigned int nbyte;
{
char buffer[BUFMAGIC];
SIGTYPE pstat;
int err;
(VOID) sprintf (buffer, "W%d\n", nbyte);
if (_rmt_command (fildes, buffer) == -1) {
return (-1);
}
pstat = signal (SIGPIPE, SIG_IGN);
if ((err = write (WRITE (fildes), buf, (NBYTETYPE) nbyte)) == nbyte) {
(VOID) signal (SIGPIPE, pstat);
return (_rmt_status (fildes));
}
if (err == -1 && errno == EINTR) {
(VOID) signal (SIGPIPE, pstat);
errno = EINTR;
return(-1);
}
(VOID) signal (SIGPIPE, pstat);
_rmt_abort (fildes);
errno = EIO;
return (-1);
}
#else
#ifdef amiga
int lattice_hack; /* Keeps Lattice 3.10 happy... */
#endif
#endif /* RMT */