Home | History | Annotate | Line # | Download | only in librmt
rmtlib.c revision 1.8.2.1
      1  1.8.2.1  thorpej /*	$NetBSD: rmtlib.c,v 1.8.2.1 1997/10/21 20:00:18 thorpej Exp $	*/
      2      1.1      jtc 
      3      1.1      jtc /*
      4      1.1      jtc  *	rmt --- remote tape emulator subroutines
      5      1.1      jtc  *
      6      1.1      jtc  *	Originally written by Jeff Lee, modified some by Arnold Robbins
      7      1.1      jtc  *
      8      1.1      jtc  *	WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
      9      1.1      jtc  *	tape protocol which rdump and rrestore use.  Unfortunately, the man
     10      1.1      jtc  *	page is *WRONG*.  The author of the routines I'm including originally
     11      1.1      jtc  *	wrote his code just based on the man page, and it didn't work, so he
     12      1.1      jtc  *	went to the rdump source to figure out why.  The only thing he had to
     13      1.1      jtc  *	change was to check for the 'F' return code in addition to the 'E',
     14      1.1      jtc  *	and to separate the various arguments with \n instead of a space.  I
     15      1.1      jtc  *	personally don't think that this is much of a problem, but I wanted to
     16      1.1      jtc  *	point it out.
     17      1.1      jtc  *	-- Arnold Robbins
     18      1.1      jtc  *
     19      1.1      jtc  *	Redone as a library that can replace open, read, write, etc, by
     20      1.1      jtc  *	Fred Fish, with some additional work by Arnold Robbins.
     21      1.1      jtc  */
     22      1.1      jtc 
     23      1.1      jtc /*
     24      1.1      jtc  *	MAXUNIT --- Maximum number of remote tape file units
     25      1.1      jtc  *
     26      1.1      jtc  *	READ --- Return the number of the read side file descriptor
     27      1.1      jtc  *	WRITE --- Return the number of the write side file descriptor
     28      1.1      jtc  */
     29      1.1      jtc 
     30      1.1      jtc #define RMTIOCTL	1
     31      1.6    mikel /* #define USE_REXEC	1 */	/* rexec code courtesy of Dan Kegel, srs!dan */
     32      1.1      jtc 
     33      1.1      jtc #include <stdio.h>
     34      1.2      jtc #include <stdlib.h>
     35      1.2      jtc #include <string.h>
     36      1.1      jtc #include <signal.h>
     37      1.1      jtc #include <sys/types.h>
     38      1.1      jtc 
     39      1.1      jtc #ifdef RMTIOCTL
     40      1.1      jtc #include <sys/ioctl.h>
     41      1.1      jtc #include <sys/mtio.h>
     42      1.1      jtc #endif
     43      1.1      jtc 
     44      1.1      jtc #ifdef USE_REXEC
     45      1.1      jtc #include <netdb.h>
     46      1.1      jtc #endif
     47      1.1      jtc 
     48      1.1      jtc #include <errno.h>
     49      1.1      jtc #include <sys/stat.h>
     50      1.1      jtc 
     51      1.2      jtc #include <fcntl.h>
     52      1.2      jtc #include <unistd.h>
     53      1.2      jtc 
     54  1.8.2.1  thorpej #define __RMTLIB_PRIVATE
     55  1.8.2.1  thorpej #include <rmt.h>		/* get prototypes for remapped functions */
     56  1.8.2.1  thorpej 
     57  1.8.2.1  thorpej #ifdef __STDC__
     58  1.8.2.1  thorpej #include <stdarg.h>
     59  1.8.2.1  thorpej #else
     60  1.8.2.1  thorpej #include <varargs.h>
     61  1.8.2.1  thorpej #endif
     62  1.8.2.1  thorpej 
     63      1.7    lukem static	int	_rmt_close __P((int));
     64      1.7    lukem static	int	_rmt_ioctl __P((int, unsigned long, char *));
     65      1.7    lukem static	off_t	_rmt_lseek __P((int, off_t, int));
     66      1.7    lukem static	int	_rmt_open __P((const char *, int, int));
     67      1.7    lukem static	int	_rmt_read __P((int, char *, unsigned int));
     68      1.7    lukem static	int	_rmt_write __P((int, const void *, unsigned int));
     69      1.7    lukem static	int	command __P((int, char *));
     70      1.7    lukem static	int	remdev __P((const char *));
     71      1.7    lukem static	void	rmtabort __P((int));
     72      1.7    lukem static	int	status __P((int));
     73      1.7    lukem 
     74      1.7    lukem 	int	isrmt __P((int));
     75      1.7    lukem 
     76      1.7    lukem 
     77      1.1      jtc #define BUFMAGIC	64	/* a magic number for buffer sizes */
     78      1.1      jtc #define MAXUNIT	4
     79      1.1      jtc 
     80      1.1      jtc #define READ(fd)	(Ctp[fd][0])
     81      1.1      jtc #define WRITE(fd)	(Ptc[fd][1])
     82      1.1      jtc 
     83      1.6    mikel static int Ctp[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
     84      1.6    mikel static int Ptc[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
     85      1.1      jtc 
     86      1.1      jtc 
     87      1.1      jtc /*
     88      1.2      jtc  *	rmtabort --- close off a remote tape connection
     89      1.1      jtc  */
     90      1.1      jtc 
     91      1.7    lukem static void
     92      1.7    lukem rmtabort(fildes)
     93      1.7    lukem 	int fildes;
     94      1.1      jtc {
     95      1.1      jtc 	close(READ(fildes));
     96      1.1      jtc 	close(WRITE(fildes));
     97      1.1      jtc 	READ(fildes) = -1;
     98      1.1      jtc 	WRITE(fildes) = -1;
     99      1.1      jtc }
    100      1.1      jtc 
    101      1.1      jtc 
    102      1.1      jtc 
    103      1.1      jtc /*
    104      1.1      jtc  *	command --- attempt to perform a remote tape command
    105      1.1      jtc  */
    106      1.1      jtc 
    107      1.7    lukem static int
    108      1.7    lukem command(fildes, buf)
    109      1.7    lukem 	int fildes;
    110      1.7    lukem 	char *buf;
    111      1.1      jtc {
    112      1.7    lukem 	int blen;
    113      1.7    lukem 	void (*pstat) __P((int));
    114      1.1      jtc 
    115      1.1      jtc /*
    116      1.1      jtc  *	save current pipe status and try to make the request
    117      1.1      jtc  */
    118      1.1      jtc 
    119      1.1      jtc 	blen = strlen(buf);
    120      1.1      jtc 	pstat = signal(SIGPIPE, SIG_IGN);
    121      1.1      jtc 	if (write(WRITE(fildes), buf, blen) == blen)
    122      1.1      jtc 	{
    123      1.1      jtc 		signal(SIGPIPE, pstat);
    124      1.1      jtc 		return(0);
    125      1.1      jtc 	}
    126      1.1      jtc 
    127      1.1      jtc /*
    128      1.1      jtc  *	something went wrong. close down and go home
    129      1.1      jtc  */
    130      1.1      jtc 
    131      1.1      jtc 	signal(SIGPIPE, pstat);
    132      1.2      jtc 	rmtabort(fildes);
    133      1.1      jtc 
    134      1.1      jtc 	errno = EIO;
    135      1.1      jtc 	return(-1);
    136      1.1      jtc }
    137      1.1      jtc 
    138      1.1      jtc 
    139      1.1      jtc 
    140      1.1      jtc /*
    141      1.1      jtc  *	status --- retrieve the status from the pipe
    142      1.1      jtc  */
    143      1.1      jtc 
    144      1.7    lukem static int
    145      1.7    lukem status(fildes)
    146      1.7    lukem 	int fildes;
    147      1.1      jtc {
    148      1.1      jtc 	int i;
    149      1.1      jtc 	char c, *cp;
    150      1.1      jtc 	char buffer[BUFMAGIC];
    151      1.1      jtc 
    152      1.1      jtc /*
    153      1.1      jtc  *	read the reply command line
    154      1.1      jtc  */
    155      1.1      jtc 
    156      1.1      jtc 	for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++)
    157      1.1      jtc 	{
    158      1.1      jtc 		if (read(READ(fildes), cp, 1) != 1)
    159      1.1      jtc 		{
    160      1.2      jtc 			rmtabort(fildes);
    161      1.1      jtc 			errno = EIO;
    162      1.1      jtc 			return(-1);
    163      1.1      jtc 		}
    164      1.1      jtc 		if (*cp == '\n')
    165      1.1      jtc 		{
    166      1.1      jtc 			*cp = 0;
    167      1.1      jtc 			break;
    168      1.1      jtc 		}
    169      1.1      jtc 	}
    170      1.1      jtc 
    171      1.1      jtc 	if (i == BUFMAGIC)
    172      1.1      jtc 	{
    173      1.2      jtc 		rmtabort(fildes);
    174      1.1      jtc 		errno = EIO;
    175      1.1      jtc 		return(-1);
    176      1.1      jtc 	}
    177      1.1      jtc 
    178      1.1      jtc /*
    179      1.1      jtc  *	check the return status
    180      1.1      jtc  */
    181      1.1      jtc 
    182      1.1      jtc 	for (cp = buffer; *cp; cp++)
    183      1.1      jtc 		if (*cp != ' ')
    184      1.1      jtc 			break;
    185      1.1      jtc 
    186      1.1      jtc 	if (*cp == 'E' || *cp == 'F')
    187      1.1      jtc 	{
    188      1.1      jtc 		errno = atoi(cp + 1);
    189      1.1      jtc 		while (read(READ(fildes), &c, 1) == 1)
    190      1.1      jtc 			if (c == '\n')
    191      1.1      jtc 				break;
    192      1.1      jtc 
    193      1.1      jtc 		if (*cp == 'F')
    194      1.2      jtc 			rmtabort(fildes);
    195      1.1      jtc 
    196      1.1      jtc 		return(-1);
    197      1.1      jtc 	}
    198      1.1      jtc 
    199      1.1      jtc /*
    200      1.1      jtc  *	check for mis-synced pipes
    201      1.1      jtc  */
    202      1.1      jtc 
    203      1.1      jtc 	if (*cp != 'A')
    204      1.1      jtc 	{
    205      1.2      jtc 		rmtabort(fildes);
    206      1.1      jtc 		errno = EIO;
    207      1.1      jtc 		return(-1);
    208      1.1      jtc 	}
    209      1.1      jtc 
    210      1.1      jtc 	return(atoi(cp + 1));
    211      1.1      jtc }
    212      1.1      jtc 
    213      1.1      jtc #ifdef USE_REXEC
    214      1.1      jtc 
    215      1.1      jtc /*
    216      1.1      jtc  * _rmt_rexec
    217      1.1      jtc  *
    218      1.1      jtc  * execute /etc/rmt on a remote system using rexec().
    219      1.1      jtc  * Return file descriptor of bidirectional socket for stdin and stdout
    220      1.1      jtc  * If username is NULL, or an empty string, uses current username.
    221      1.1      jtc  *
    222      1.1      jtc  * ADR: By default, this code is not used, since it requires that
    223      1.1      jtc  * the user have a .netrc file in his/her home directory, or that the
    224      1.1      jtc  * application designer be willing to have rexec prompt for login and
    225      1.1      jtc  * password info. This may be unacceptable, and .rhosts files for use
    226      1.1      jtc  * with rsh are much more common on BSD systems.
    227      1.1      jtc  */
    228      1.1      jtc 
    229      1.7    lukem static	int	_rmt_rexec __P((const char *, const char *));
    230      1.7    lukem 
    231      1.1      jtc static int
    232      1.1      jtc _rmt_rexec(host, user)
    233      1.7    lukem 	const char *host;
    234      1.7    lukem 	const char *user;		/* may be NULL */
    235      1.1      jtc {
    236      1.1      jtc 	struct servent *rexecserv;
    237      1.1      jtc 
    238      1.1      jtc 	rexecserv = getservbyname("exec", "tcp");
    239      1.1      jtc 	if (NULL == rexecserv) {
    240      1.1      jtc 		fprintf (stderr, "? exec/tcp: service not available.");
    241      1.1      jtc 		exit (-1);
    242      1.1      jtc 	}
    243      1.1      jtc 	if ((user != NULL) && *user == '\0')
    244      1.1      jtc 		user = (char *) NULL;
    245      1.1      jtc 	return rexec (&host, rexecserv->s_port, user, NULL,
    246      1.1      jtc 			"/etc/rmt", (int *)NULL);
    247      1.1      jtc }
    248      1.1      jtc #endif /* USE_REXEC */
    249      1.1      jtc 
    250      1.1      jtc /*
    251      1.1      jtc  *	_rmt_open --- open a magtape device on system specified, as given user
    252      1.1      jtc  *
    253      1.1      jtc  *	file name has the form [user@]system:/dev/????
    254      1.1      jtc #ifdef COMPAT
    255      1.1      jtc  *	file name has the form system[.user]:/dev/????
    256      1.1      jtc #endif
    257      1.1      jtc  */
    258      1.1      jtc 
    259      1.1      jtc #define MAXHOSTLEN	257	/* BSD allows very long host names... */
    260      1.1      jtc 
    261      1.7    lukem static int
    262      1.7    lukem _rmt_open(path, oflag, mode)
    263      1.7    lukem 	const char *path;
    264      1.7    lukem 	int oflag;
    265      1.7    lukem 	int mode;
    266      1.1      jtc {
    267      1.1      jtc 	int i, rc;
    268      1.1      jtc 	char buffer[BUFMAGIC];
    269      1.1      jtc 	char system[MAXHOSTLEN];
    270      1.1      jtc 	char device[BUFMAGIC];
    271      1.1      jtc 	char login[BUFMAGIC];
    272      1.1      jtc 	char *sys, *dev, *user;
    273      1.1      jtc 
    274      1.1      jtc 	sys = system;
    275      1.1      jtc 	dev = device;
    276      1.1      jtc 	user = login;
    277      1.1      jtc 
    278      1.1      jtc /*
    279      1.1      jtc  *	first, find an open pair of file descriptors
    280      1.1      jtc  */
    281      1.1      jtc 
    282      1.1      jtc 	for (i = 0; i < MAXUNIT; i++)
    283      1.1      jtc 		if (READ(i) == -1 && WRITE(i) == -1)
    284      1.1      jtc 			break;
    285      1.1      jtc 
    286      1.1      jtc 	if (i == MAXUNIT)
    287      1.1      jtc 	{
    288      1.1      jtc 		errno = EMFILE;
    289      1.1      jtc 		return(-1);
    290      1.1      jtc 	}
    291      1.1      jtc 
    292      1.1      jtc /*
    293      1.1      jtc  *	pull apart system and device, and optional user
    294      1.1      jtc  *	don't munge original string
    295      1.1      jtc  *	if COMPAT is defined, also handle old (4.2) style person.site notation.
    296      1.1      jtc  */
    297      1.1      jtc 
    298      1.1      jtc 	while (*path != '@'
    299      1.1      jtc #ifdef COMPAT
    300      1.1      jtc 			&& *path != '.'
    301      1.1      jtc #endif
    302      1.1      jtc 			&& *path != ':') {
    303      1.1      jtc 		*sys++ = *path++;
    304      1.1      jtc 	}
    305      1.1      jtc 	*sys = '\0';
    306      1.1      jtc 	path++;
    307      1.1      jtc 
    308      1.1      jtc 	if (*(path - 1) == '@')
    309      1.1      jtc 	{
    310      1.5      mrg 		(void)strncpy(user, system, sizeof(login) - 1);
    311      1.5      mrg 				/* saw user part of user@host */
    312      1.1      jtc 		sys = system;			/* start over */
    313      1.1      jtc 		while (*path != ':') {
    314      1.1      jtc 			*sys++ = *path++;
    315      1.1      jtc 		}
    316      1.1      jtc 		*sys = '\0';
    317      1.1      jtc 		path++;
    318      1.1      jtc 	}
    319      1.1      jtc #ifdef COMPAT
    320      1.1      jtc 	else if (*(path - 1) == '.')
    321      1.1      jtc 	{
    322      1.1      jtc 		while (*path != ':') {
    323      1.1      jtc 			*user++ = *path++;
    324      1.1      jtc 		}
    325      1.1      jtc 		*user = '\0';
    326      1.1      jtc 		path++;
    327      1.1      jtc 	}
    328      1.1      jtc #endif
    329      1.1      jtc 	else
    330      1.1      jtc 		*user = '\0';
    331      1.1      jtc 
    332      1.1      jtc 	while (*path) {
    333      1.1      jtc 		*dev++ = *path++;
    334      1.1      jtc 	}
    335      1.1      jtc 	*dev = '\0';
    336      1.1      jtc 
    337      1.1      jtc #ifdef USE_REXEC
    338      1.1      jtc /*
    339      1.1      jtc  *	Execute the remote command using rexec
    340      1.1      jtc  */
    341      1.1      jtc 	READ(i) = WRITE(i) = _rmt_rexec(system, login);
    342      1.1      jtc 	if (READ(i) < 0)
    343      1.1      jtc 		return -1;
    344      1.1      jtc #else
    345      1.1      jtc /*
    346      1.1      jtc  *	setup the pipes for the 'rsh' command and fork
    347      1.1      jtc  */
    348      1.1      jtc 
    349      1.1      jtc 	if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
    350      1.1      jtc 		return(-1);
    351      1.1      jtc 
    352      1.1      jtc 	if ((rc = fork()) == -1)
    353      1.1      jtc 		return(-1);
    354      1.1      jtc 
    355      1.1      jtc 	if (rc == 0)
    356      1.1      jtc 	{
    357      1.1      jtc 		close(0);
    358      1.1      jtc 		dup(Ptc[i][0]);
    359      1.1      jtc 		close(Ptc[i][0]); close(Ptc[i][1]);
    360      1.1      jtc 		close(1);
    361      1.1      jtc 		dup(Ctp[i][1]);
    362      1.1      jtc 		close(Ctp[i][0]); close(Ctp[i][1]);
    363      1.1      jtc 		(void) setuid (getuid ());
    364      1.1      jtc 		(void) setgid (getgid ());
    365      1.1      jtc 		if (*login)
    366      1.1      jtc 		{
    367      1.3      jtc 			execl("/usr/bin/rsh", "rsh", system, "-l", login,
    368      1.1      jtc 				"/etc/rmt", (char *) 0);
    369      1.1      jtc 		}
    370      1.1      jtc 		else
    371      1.1      jtc 		{
    372      1.3      jtc 			execl("/usr/bin/rsh", "rsh", system,
    373      1.1      jtc 				"/etc/rmt", (char *) 0);
    374      1.1      jtc 		}
    375      1.1      jtc 
    376      1.1      jtc /*
    377      1.1      jtc  *	bad problems if we get here
    378      1.1      jtc  */
    379      1.1      jtc 
    380      1.1      jtc 		perror("exec");
    381      1.1      jtc 		exit(1);
    382      1.1      jtc 	}
    383      1.1      jtc 
    384      1.1      jtc 	close(Ptc[i][0]); close(Ctp[i][1]);
    385      1.1      jtc #endif
    386      1.1      jtc 
    387      1.1      jtc /*
    388      1.1      jtc  *	now attempt to open the tape device
    389      1.1      jtc  */
    390      1.1      jtc 
    391      1.5      mrg 	(void)snprintf(buffer, sizeof(buffer), "O%s\n%d\n", device, oflag);
    392      1.1      jtc 	if (command(i, buffer) == -1 || status(i) == -1)
    393      1.1      jtc 		return(-1);
    394      1.1      jtc 
    395      1.1      jtc 	return(i);
    396      1.1      jtc }
    397      1.1      jtc 
    398      1.1      jtc 
    399      1.1      jtc 
    400      1.1      jtc /*
    401      1.1      jtc  *	_rmt_close --- close a remote magtape unit and shut down
    402      1.1      jtc  */
    403      1.1      jtc 
    404      1.7    lukem static int
    405      1.7    lukem _rmt_close(fildes)
    406      1.7    lukem 	int fildes;
    407      1.1      jtc {
    408      1.1      jtc 	int rc;
    409      1.1      jtc 
    410      1.1      jtc 	if (command(fildes, "C\n") != -1)
    411      1.1      jtc 	{
    412      1.1      jtc 		rc = status(fildes);
    413      1.1      jtc 
    414      1.2      jtc 		rmtabort(fildes);
    415      1.1      jtc 		return(rc);
    416      1.1      jtc 	}
    417      1.1      jtc 
    418      1.1      jtc 	return(-1);
    419      1.1      jtc }
    420      1.1      jtc 
    421      1.1      jtc 
    422      1.1      jtc 
    423      1.1      jtc /*
    424      1.1      jtc  *	_rmt_read --- read a buffer from a remote tape
    425      1.1      jtc  */
    426      1.1      jtc 
    427      1.7    lukem static int
    428      1.7    lukem _rmt_read(fildes, buf, nbyte)
    429      1.7    lukem 	int fildes;
    430      1.7    lukem 	char *buf;
    431      1.7    lukem 	unsigned int nbyte;
    432      1.1      jtc {
    433      1.1      jtc 	int rc, i;
    434      1.1      jtc 	char buffer[BUFMAGIC];
    435      1.1      jtc 
    436      1.5      mrg 	(void)snprintf(buffer, sizeof buffer, "R%d\n", nbyte);
    437      1.1      jtc 	if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
    438      1.1      jtc 		return(-1);
    439      1.1      jtc 
    440      1.1      jtc 	for (i = 0; i < rc; i += nbyte, buf += nbyte)
    441      1.1      jtc 	{
    442      1.1      jtc 		nbyte = read(READ(fildes), buf, rc);
    443      1.1      jtc 		if (nbyte <= 0)
    444      1.1      jtc 		{
    445      1.2      jtc 			rmtabort(fildes);
    446      1.1      jtc 			errno = EIO;
    447      1.1      jtc 			return(-1);
    448      1.1      jtc 		}
    449      1.1      jtc 	}
    450      1.1      jtc 
    451      1.1      jtc 	return(rc);
    452      1.1      jtc }
    453      1.1      jtc 
    454      1.1      jtc 
    455      1.1      jtc 
    456      1.1      jtc /*
    457      1.1      jtc  *	_rmt_write --- write a buffer to the remote tape
    458      1.1      jtc  */
    459      1.1      jtc 
    460      1.7    lukem static int
    461      1.7    lukem _rmt_write(fildes, buf, nbyte)
    462      1.7    lukem 	int fildes;
    463      1.7    lukem 	const void *buf;
    464      1.7    lukem 	unsigned int nbyte;
    465      1.1      jtc {
    466      1.1      jtc 	char buffer[BUFMAGIC];
    467      1.7    lukem 	void (*pstat) __P((int));
    468      1.1      jtc 
    469      1.5      mrg 	(void)snprintf(buffer, sizeof buffer, "W%d\n", nbyte);
    470      1.1      jtc 	if (command(fildes, buffer) == -1)
    471      1.1      jtc 		return(-1);
    472      1.1      jtc 
    473      1.1      jtc 	pstat = signal(SIGPIPE, SIG_IGN);
    474      1.1      jtc 	if (write(WRITE(fildes), buf, nbyte) == nbyte)
    475      1.1      jtc 	{
    476      1.1      jtc 		signal (SIGPIPE, pstat);
    477      1.1      jtc 		return(status(fildes));
    478      1.1      jtc 	}
    479      1.1      jtc 
    480      1.1      jtc 	signal (SIGPIPE, pstat);
    481      1.2      jtc 	rmtabort(fildes);
    482      1.1      jtc 	errno = EIO;
    483      1.1      jtc 	return(-1);
    484      1.1      jtc }
    485      1.1      jtc 
    486      1.1      jtc 
    487      1.1      jtc 
    488      1.1      jtc /*
    489      1.1      jtc  *	_rmt_lseek --- perform an imitation lseek operation remotely
    490      1.1      jtc  */
    491      1.1      jtc 
    492      1.7    lukem static off_t
    493      1.7    lukem _rmt_lseek(fildes, offset, whence)
    494      1.7    lukem 	int fildes;
    495      1.7    lukem 	off_t offset;
    496      1.7    lukem 	int whence;
    497      1.1      jtc {
    498      1.1      jtc 	char buffer[BUFMAGIC];
    499      1.1      jtc 
    500      1.8      mrg 	(void)snprintf(buffer, sizeof buffer, "L%qd\n%d\n", (long long)offset,
    501      1.8      mrg 	    whence);
    502      1.1      jtc 	if (command(fildes, buffer) == -1)
    503      1.1      jtc 		return(-1);
    504      1.1      jtc 
    505      1.1      jtc 	return(status(fildes));
    506      1.1      jtc }
    507      1.1      jtc 
    508      1.1      jtc 
    509      1.1      jtc /*
    510      1.1      jtc  *	_rmt_ioctl --- perform raw tape operations remotely
    511      1.1      jtc  */
    512      1.1      jtc 
    513      1.1      jtc #ifdef RMTIOCTL
    514      1.7    lukem static int
    515      1.7    lukem _rmt_ioctl(fildes, op, arg)
    516      1.7    lukem 	int fildes;
    517      1.7    lukem 	unsigned long op;
    518      1.7    lukem 	char *arg;
    519      1.1      jtc {
    520      1.1      jtc 	char c;
    521      1.1      jtc 	int rc, cnt;
    522      1.1      jtc 	char buffer[BUFMAGIC];
    523      1.1      jtc 
    524      1.1      jtc /*
    525      1.1      jtc  *	MTIOCOP is the easy one. nothing is transfered in binary
    526      1.1      jtc  */
    527      1.1      jtc 
    528      1.1      jtc 	if (op == MTIOCTOP)
    529      1.1      jtc 	{
    530      1.5      mrg 		(void)snprintf(buffer, sizeof buffer, "I%d\n%d\n",
    531      1.5      mrg 		    ((struct mtop *)arg)->mt_op,
    532      1.5      mrg 		    ((struct mtop *)arg)->mt_count);
    533      1.1      jtc 		if (command(fildes, buffer) == -1)
    534      1.1      jtc 			return(-1);
    535      1.1      jtc 		return(status(fildes));
    536      1.1      jtc 	}
    537      1.1      jtc 
    538      1.1      jtc /*
    539      1.1      jtc  *	we can only handle 2 ops, if not the other one, punt
    540      1.1      jtc  */
    541      1.1      jtc 
    542      1.1      jtc 	if (op != MTIOCGET)
    543      1.1      jtc 	{
    544      1.1      jtc 		errno = EINVAL;
    545      1.1      jtc 		return(-1);
    546      1.1      jtc 	}
    547      1.1      jtc 
    548      1.1      jtc /*
    549      1.1      jtc  *	grab the status and read it directly into the structure
    550      1.1      jtc  *	this assumes that the status buffer is (hopefully) not
    551      1.1      jtc  *	padded and that 2 shorts fit in a long without any word
    552      1.1      jtc  *	alignment problems, ie - the whole struct is contiguous
    553      1.1      jtc  *	NOTE - this is probably NOT a good assumption.
    554      1.1      jtc  */
    555      1.1      jtc 
    556      1.1      jtc 	if (command(fildes, "S") == -1 || (rc = status(fildes)) == -1)
    557      1.1      jtc 		return(-1);
    558      1.1      jtc 
    559      1.1      jtc 	for (; rc > 0; rc -= cnt, arg += cnt)
    560      1.1      jtc 	{
    561      1.1      jtc 		cnt = read(READ(fildes), arg, rc);
    562      1.1      jtc 		if (cnt <= 0)
    563      1.1      jtc 		{
    564      1.2      jtc 			rmtabort(fildes);
    565      1.1      jtc 			errno = EIO;
    566      1.1      jtc 			return(-1);
    567      1.1      jtc 		}
    568      1.1      jtc 	}
    569      1.1      jtc 
    570      1.1      jtc /*
    571      1.1      jtc  *	now we check for byte position. mt_type is a small integer field
    572      1.1      jtc  *	(normally) so we will check its magnitude. if it is larger than
    573      1.1      jtc  *	256, we will assume that the bytes are swapped and go through
    574      1.1      jtc  *	and reverse all the bytes
    575      1.1      jtc  */
    576      1.1      jtc 
    577      1.1      jtc 	if (((struct mtget *) arg)->mt_type < 256)
    578      1.1      jtc 		return(0);
    579      1.1      jtc 
    580      1.1      jtc 	for (cnt = 0; cnt < rc; cnt += 2)
    581      1.1      jtc 	{
    582      1.1      jtc 		c = arg[cnt];
    583      1.1      jtc 		arg[cnt] = arg[cnt+1];
    584      1.1      jtc 		arg[cnt+1] = c;
    585      1.1      jtc 	}
    586      1.1      jtc 
    587      1.1      jtc 	return(0);
    588      1.1      jtc   }
    589      1.1      jtc #endif /* RMTIOCTL */
    590      1.1      jtc 
    591      1.1      jtc /*
    592      1.1      jtc  *	Added routines to replace open(), close(), lseek(), ioctl(), etc.
    593      1.1      jtc  *	The preprocessor can be used to remap these the rmtopen(), etc
    594      1.1      jtc  *	thus minimizing source changes:
    595      1.1      jtc  *
    596      1.1      jtc  *		#ifdef <something>
    597      1.1      jtc  *		#  define access rmtaccess
    598      1.1      jtc  *		#  define close rmtclose
    599      1.1      jtc  *		#  define creat rmtcreat
    600      1.1      jtc  *		#  define dup rmtdup
    601      1.1      jtc  *		#  define fcntl rmtfcntl
    602      1.1      jtc  *		#  define fstat rmtfstat
    603      1.1      jtc  *		#  define ioctl rmtioctl
    604      1.1      jtc  *		#  define isatty rmtisatty
    605      1.1      jtc  *		#  define lseek rmtlseek
    606      1.1      jtc  *		#  define lstat rmtlstat
    607      1.1      jtc  *		#  define open rmtopen
    608      1.1      jtc  *		#  define read rmtread
    609      1.1      jtc  *		#  define stat rmtstat
    610      1.1      jtc  *		#  define write rmtwrite
    611      1.1      jtc  *		#endif
    612      1.1      jtc  *
    613      1.1      jtc  *	-- Fred Fish
    614      1.1      jtc  *
    615      1.1      jtc  *	ADR --- I set up a <rmt.h> include file for this
    616      1.1      jtc  *
    617      1.1      jtc  */
    618      1.1      jtc 
    619      1.1      jtc /*
    620      1.1      jtc  *	Note that local vs remote file descriptors are distinquished
    621      1.1      jtc  *	by adding a bias to the remote descriptors.  This is a quick
    622      1.1      jtc  *	and dirty trick that may not be portable to some systems.
    623      1.1      jtc  */
    624      1.1      jtc 
    625      1.1      jtc #define REM_BIAS 128
    626      1.1      jtc 
    627      1.1      jtc 
    628      1.1      jtc /*
    629      1.1      jtc  *	Test pathname to see if it is local or remote.  A remote device
    630      1.1      jtc  *	is any string that contains ":/dev/".  Returns 1 if remote,
    631      1.1      jtc  *	0 otherwise.
    632      1.1      jtc  */
    633      1.1      jtc 
    634      1.7    lukem static int
    635      1.7    lukem remdev(path)
    636      1.7    lukem 	const char *path;
    637      1.1      jtc {
    638      1.1      jtc 	if ((path = strchr (path, ':')) != NULL)
    639      1.1      jtc 	{
    640      1.1      jtc 		if (strncmp (path + 1, "/dev/", 5) == 0)
    641      1.1      jtc 		{
    642      1.1      jtc 			return (1);
    643      1.1      jtc 		}
    644      1.1      jtc 	}
    645      1.1      jtc 	return (0);
    646      1.1      jtc }
    647      1.1      jtc 
    648      1.1      jtc 
    649      1.1      jtc /*
    650      1.1      jtc  *	Open a local or remote file.  Looks just like open(2) to
    651      1.1      jtc  *	caller.
    652      1.1      jtc  */
    653      1.1      jtc 
    654      1.7    lukem int
    655  1.8.2.1  thorpej #ifdef __STDC__
    656  1.8.2.1  thorpej rmtopen(const char *path, int oflag, ...)
    657  1.8.2.1  thorpej #else
    658  1.8.2.1  thorpej rmtopen(va_alist)
    659  1.8.2.1  thorpej 	va_decl
    660  1.8.2.1  thorpej #endif
    661      1.1      jtc {
    662  1.8.2.1  thorpej 	mode_t mode;
    663      1.1      jtc 	int fd;
    664  1.8.2.1  thorpej 	va_list ap;
    665  1.8.2.1  thorpej #if __STDC__
    666  1.8.2.1  thorpej 	va_start(ap, oflag);
    667  1.8.2.1  thorpej #else
    668  1.8.2.1  thorpej 	const char *path;
    669  1.8.2.1  thorpej 	int oflag;
    670  1.8.2.1  thorpej 
    671  1.8.2.1  thorpej 	va_start(ap);
    672  1.8.2.1  thorpej 	path = va_arg(ap, const char *);
    673  1.8.2.1  thorpej 	oflag = va_arg(ap, int);
    674  1.8.2.1  thorpej #endif
    675  1.8.2.1  thorpej 
    676  1.8.2.1  thorpej 	mode = va_arg(ap, mode_t);
    677  1.8.2.1  thorpej 	va_end(ap);
    678      1.1      jtc 
    679      1.1      jtc 	if (remdev (path))
    680      1.1      jtc 	{
    681      1.1      jtc 		fd = _rmt_open (path, oflag, mode);
    682      1.1      jtc 
    683      1.1      jtc 		return (fd == -1) ? -1 : (fd + REM_BIAS);
    684      1.1      jtc 	}
    685      1.1      jtc 	else
    686      1.1      jtc 	{
    687      1.1      jtc 		return (open (path, oflag, mode));
    688      1.1      jtc 	}
    689      1.1      jtc }
    690      1.1      jtc 
    691      1.1      jtc /*
    692      1.1      jtc  *	Test pathname for specified access.  Looks just like access(2)
    693      1.1      jtc  *	to caller.
    694      1.1      jtc  */
    695      1.1      jtc 
    696      1.7    lukem int
    697      1.7    lukem rmtaccess(path, amode)
    698      1.7    lukem 	const char *path;
    699      1.7    lukem 	int amode;
    700      1.1      jtc {
    701      1.1      jtc 	if (remdev (path))
    702      1.1      jtc 	{
    703      1.1      jtc 		return (0);		/* Let /etc/rmt find out */
    704      1.1      jtc 	}
    705      1.1      jtc 	else
    706      1.1      jtc 	{
    707      1.1      jtc 		return (access (path, amode));
    708      1.1      jtc 	}
    709      1.1      jtc }
    710      1.1      jtc 
    711      1.1      jtc 
    712      1.1      jtc /*
    713      1.6    mikel  *	Isrmt. Let a programmer know he has a remote device.
    714      1.6    mikel  */
    715      1.6    mikel 
    716      1.7    lukem int
    717      1.7    lukem isrmt(fd)
    718      1.7    lukem 	int fd;
    719      1.6    mikel {
    720      1.6    mikel 	return (fd >= REM_BIAS);
    721      1.6    mikel }
    722      1.6    mikel 
    723      1.6    mikel 
    724      1.6    mikel /*
    725      1.1      jtc  *	Read from stream.  Looks just like read(2) to caller.
    726      1.1      jtc  */
    727      1.1      jtc 
    728      1.7    lukem ssize_t
    729      1.7    lukem rmtread(fildes, buf, nbyte)
    730      1.7    lukem 	int fildes;
    731      1.7    lukem 	void *buf;
    732      1.7    lukem 	size_t nbyte;
    733      1.1      jtc {
    734      1.1      jtc 	if (isrmt (fildes))
    735      1.1      jtc 	{
    736      1.1      jtc 		return (_rmt_read (fildes - REM_BIAS, buf, nbyte));
    737      1.1      jtc 	}
    738      1.1      jtc 	else
    739      1.1      jtc 	{
    740      1.1      jtc 		return (read (fildes, buf, nbyte));
    741      1.1      jtc 	}
    742      1.1      jtc }
    743      1.1      jtc 
    744      1.1      jtc 
    745      1.1      jtc /*
    746      1.1      jtc  *	Write to stream.  Looks just like write(2) to caller.
    747      1.1      jtc  */
    748      1.1      jtc 
    749      1.7    lukem ssize_t
    750      1.7    lukem rmtwrite(fildes, buf, nbyte)
    751      1.7    lukem 	int fildes;
    752      1.7    lukem 	const void *buf;
    753      1.7    lukem 	size_t nbyte;
    754      1.1      jtc {
    755      1.1      jtc 	if (isrmt (fildes))
    756      1.1      jtc 	{
    757      1.1      jtc 		return (_rmt_write (fildes - REM_BIAS, buf, nbyte));
    758      1.1      jtc 	}
    759      1.1      jtc 	else
    760      1.1      jtc 	{
    761      1.1      jtc 		return (write (fildes, buf, nbyte));
    762      1.1      jtc 	}
    763      1.1      jtc }
    764      1.1      jtc 
    765      1.1      jtc /*
    766      1.1      jtc  *	Perform lseek on file.  Looks just like lseek(2) to caller.
    767      1.1      jtc  */
    768      1.1      jtc 
    769      1.7    lukem off_t
    770      1.7    lukem rmtlseek(fildes, offset, whence)
    771      1.7    lukem 	int fildes;
    772      1.7    lukem 	off_t offset;
    773      1.7    lukem 	int whence;
    774      1.1      jtc {
    775      1.1      jtc 	if (isrmt (fildes))
    776      1.1      jtc 	{
    777      1.1      jtc 		return (_rmt_lseek (fildes - REM_BIAS, offset, whence));
    778      1.1      jtc 	}
    779      1.1      jtc 	else
    780      1.1      jtc 	{
    781      1.1      jtc 		return (lseek (fildes, offset, whence));
    782      1.1      jtc 	}
    783      1.1      jtc }
    784      1.1      jtc 
    785      1.1      jtc 
    786      1.1      jtc /*
    787      1.1      jtc  *	Close a file.  Looks just like close(2) to caller.
    788      1.1      jtc  */
    789      1.1      jtc 
    790      1.7    lukem int
    791      1.7    lukem rmtclose(fildes)
    792      1.7    lukem 	int fildes;
    793      1.1      jtc {
    794      1.1      jtc 	if (isrmt (fildes))
    795      1.1      jtc 	{
    796      1.1      jtc 		return (_rmt_close (fildes - REM_BIAS));
    797      1.1      jtc 	}
    798      1.1      jtc 	else
    799      1.1      jtc 	{
    800      1.1      jtc 		return (close (fildes));
    801      1.1      jtc 	}
    802      1.1      jtc }
    803      1.1      jtc 
    804      1.1      jtc /*
    805      1.1      jtc  *	Do ioctl on file.  Looks just like ioctl(2) to caller.
    806      1.1      jtc  */
    807      1.1      jtc 
    808      1.7    lukem int
    809  1.8.2.1  thorpej #ifdef __STDC__
    810  1.8.2.1  thorpej rmtioctl(int fildes, unsigned long request, ...)
    811  1.8.2.1  thorpej #else
    812  1.8.2.1  thorpej rmtioctl(va_alist)
    813  1.8.2.1  thorpej 	va_decl
    814  1.8.2.1  thorpej #endif
    815  1.8.2.1  thorpej {
    816  1.8.2.1  thorpej 	char *arg;
    817  1.8.2.1  thorpej 	va_list ap;
    818  1.8.2.1  thorpej #if __STDC__
    819  1.8.2.1  thorpej 	va_start(ap, request);
    820  1.8.2.1  thorpej #else
    821      1.7    lukem 	int fildes;
    822      1.7    lukem 	unsigned long request;
    823  1.8.2.1  thorpej 
    824  1.8.2.1  thorpej 	va_start(ap);
    825  1.8.2.1  thorpej 	filedes = va_arg(ap, int);
    826  1.8.2.1  thorpej 	request = va_arg(ap, unsigned long);
    827  1.8.2.1  thorpej #endif
    828  1.8.2.1  thorpej 
    829  1.8.2.1  thorpej 	arg = va_arg(ap, char *);
    830  1.8.2.1  thorpej 	va_end(ap);
    831  1.8.2.1  thorpej 
    832      1.1      jtc 	if (isrmt (fildes))
    833      1.1      jtc 	{
    834      1.1      jtc #ifdef RMTIOCTL
    835      1.1      jtc 		return (_rmt_ioctl (fildes - REM_BIAS, request, arg));
    836      1.1      jtc #else
    837      1.1      jtc 		errno = EOPNOTSUPP;
    838      1.1      jtc 		return (-1);		/* For now  (fnf) */
    839      1.1      jtc #endif
    840      1.1      jtc 	}
    841      1.1      jtc 	else
    842      1.1      jtc 	{
    843      1.1      jtc 		return (ioctl (fildes, request, arg));
    844      1.1      jtc 	}
    845      1.1      jtc }
    846      1.1      jtc 
    847      1.1      jtc 
    848      1.1      jtc /*
    849      1.1      jtc  *	Duplicate an open file descriptor.  Looks just like dup(2)
    850      1.1      jtc  *	to caller.
    851      1.1      jtc  */
    852      1.1      jtc 
    853      1.7    lukem int
    854      1.7    lukem rmtdup(fildes)
    855      1.7    lukem 	int fildes;
    856      1.1      jtc {
    857      1.1      jtc 	if (isrmt (fildes))
    858      1.1      jtc 	{
    859      1.1      jtc 		errno = EOPNOTSUPP;
    860      1.1      jtc 		return (-1);		/* For now (fnf) */
    861      1.1      jtc 	}
    862      1.1      jtc 	else
    863      1.1      jtc 	{
    864      1.1      jtc 		return (dup (fildes));
    865      1.1      jtc 	}
    866      1.1      jtc }
    867      1.1      jtc 
    868      1.1      jtc /*
    869      1.1      jtc  *	Get file status.  Looks just like fstat(2) to caller.
    870      1.1      jtc  */
    871      1.1      jtc 
    872      1.7    lukem int
    873      1.7    lukem rmtfstat(fildes, buf)
    874      1.7    lukem 	int fildes;
    875      1.7    lukem 	struct stat *buf;
    876      1.1      jtc {
    877      1.1      jtc 	if (isrmt (fildes))
    878      1.1      jtc 	{
    879      1.1      jtc 		errno = EOPNOTSUPP;
    880      1.1      jtc 		return (-1);		/* For now (fnf) */
    881      1.1      jtc 	}
    882      1.1      jtc 	else
    883      1.1      jtc 	{
    884      1.1      jtc 		return (fstat (fildes, buf));
    885      1.1      jtc 	}
    886      1.1      jtc }
    887      1.1      jtc 
    888      1.1      jtc 
    889      1.1      jtc /*
    890      1.1      jtc  *	Get file status.  Looks just like stat(2) to caller.
    891      1.1      jtc  */
    892      1.1      jtc 
    893      1.7    lukem int
    894      1.7    lukem rmtstat(path, buf)
    895      1.7    lukem 	const char *path;
    896      1.7    lukem 	struct stat *buf;
    897      1.1      jtc {
    898      1.1      jtc 	if (remdev (path))
    899      1.1      jtc 	{
    900      1.1      jtc 		errno = EOPNOTSUPP;
    901      1.1      jtc 		return (-1);		/* For now (fnf) */
    902      1.1      jtc 	}
    903      1.1      jtc 	else
    904      1.1      jtc 	{
    905      1.1      jtc 		return (stat (path, buf));
    906      1.1      jtc 	}
    907      1.1      jtc }
    908      1.1      jtc 
    909      1.1      jtc 
    910      1.1      jtc 
    911      1.1      jtc /*
    912      1.1      jtc  *	Create a file from scratch.  Looks just like creat(2) to the caller.
    913      1.1      jtc  */
    914      1.1      jtc 
    915      1.7    lukem int
    916      1.7    lukem rmtcreat(path, mode)
    917      1.7    lukem 	const char *path;
    918      1.7    lukem 	mode_t mode;
    919      1.1      jtc {
    920      1.1      jtc 	if (remdev (path))
    921      1.1      jtc 	{
    922      1.1      jtc 		return (rmtopen (path, 1 | O_CREAT, mode));
    923      1.1      jtc 	}
    924      1.1      jtc 	else
    925      1.1      jtc 	{
    926      1.1      jtc 		return (creat (path, mode));
    927      1.1      jtc 	}
    928      1.1      jtc }
    929      1.1      jtc 
    930      1.1      jtc /*
    931      1.1      jtc  *	Rmtfcntl. Do a remote fcntl operation.
    932      1.1      jtc  */
    933      1.1      jtc 
    934      1.7    lukem int
    935  1.8.2.1  thorpej #ifdef __STDC__
    936  1.8.2.1  thorpej rmtfcntl(int fd, int cmd, ...)
    937  1.8.2.1  thorpej #else
    938  1.8.2.1  thorpej rmtfcntl(va_alist)
    939  1.8.2.1  thorpej 	va_decl
    940  1.8.2.1  thorpej #endif
    941      1.1      jtc {
    942  1.8.2.1  thorpej 	void *arg;
    943  1.8.2.1  thorpej 	va_list ap;
    944  1.8.2.1  thorpej #if __STDC__
    945  1.8.2.1  thorpej 	va_start(ap, cmd);
    946  1.8.2.1  thorpej #else
    947  1.8.2.1  thorpej 	int fd, cmd;
    948  1.8.2.1  thorpej 
    949  1.8.2.1  thorpej 	va_start(ap);
    950  1.8.2.1  thorpej 	fd = va_arg(ap, int);
    951  1.8.2.1  thorpej 	cmd = va_arg(ap, int);
    952  1.8.2.1  thorpej #endif
    953  1.8.2.1  thorpej 
    954  1.8.2.1  thorpej 	arg = va_arg(ap, void *);
    955  1.8.2.1  thorpej 	va_end(ap);
    956  1.8.2.1  thorpej 
    957      1.1      jtc 	if (isrmt (fd))
    958      1.1      jtc 	{
    959      1.1      jtc 		errno = EOPNOTSUPP;
    960      1.1      jtc 		return (-1);
    961      1.1      jtc 	}
    962      1.1      jtc 	else
    963      1.1      jtc 	{
    964      1.1      jtc 		return (fcntl (fd, cmd, arg));
    965      1.1      jtc 	}
    966      1.1      jtc }
    967      1.1      jtc 
    968      1.1      jtc /*
    969      1.1      jtc  *	Rmtisatty.  Do the isatty function.
    970      1.1      jtc  */
    971      1.1      jtc 
    972      1.7    lukem int
    973      1.7    lukem rmtisatty(fd)
    974      1.7    lukem 	int fd;
    975      1.1      jtc {
    976      1.1      jtc 	if (isrmt (fd))
    977      1.1      jtc 		return (0);
    978      1.1      jtc 	else
    979      1.1      jtc 		return (isatty (fd));
    980      1.1      jtc }
    981      1.1      jtc 
    982      1.1      jtc 
    983      1.1      jtc /*
    984      1.1      jtc  *	Get file status, even if symlink.  Looks just like lstat(2) to caller.
    985      1.1      jtc  */
    986      1.1      jtc 
    987      1.7    lukem int
    988      1.7    lukem rmtlstat(path, buf)
    989      1.7    lukem 	const char *path;
    990      1.7    lukem 	struct stat *buf;
    991      1.1      jtc {
    992      1.1      jtc 	if (remdev (path))
    993      1.1      jtc 	{
    994      1.1      jtc 		errno = EOPNOTSUPP;
    995      1.1      jtc 		return (-1);		/* For now (fnf) */
    996      1.1      jtc 	}
    997      1.1      jtc 	else
    998      1.1      jtc 	{
    999      1.1      jtc 		return (lstat (path, buf));
   1000      1.1      jtc 	}
   1001      1.1      jtc }
   1002