xref: /minix3/lib/librmt/rmtlib.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
185fee539SLionel Sambuc /*	$NetBSD: rmtlib.c,v 1.26 2012/03/21 10:10:37 matt Exp $	*/
285fee539SLionel Sambuc 
385fee539SLionel Sambuc /*
485fee539SLionel Sambuc  *	rmt --- remote tape emulator subroutines
585fee539SLionel Sambuc  *
685fee539SLionel Sambuc  *	Originally written by Jeff Lee, modified some by Arnold Robbins
785fee539SLionel Sambuc  *
885fee539SLionel Sambuc  *	WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
985fee539SLionel Sambuc  *	tape protocol which rdump and rrestore use.  Unfortunately, the man
1085fee539SLionel Sambuc  *	page is *WRONG*.  The author of the routines I'm including originally
1185fee539SLionel Sambuc  *	wrote his code just based on the man page, and it didn't work, so he
1285fee539SLionel Sambuc  *	went to the rdump source to figure out why.  The only thing he had to
1385fee539SLionel Sambuc  *	change was to check for the 'F' return code in addition to the 'E',
1485fee539SLionel Sambuc  *	and to separate the various arguments with \n instead of a space.  I
1585fee539SLionel Sambuc  *	personally don't think that this is much of a problem, but I wanted to
1685fee539SLionel Sambuc  *	point it out.
1785fee539SLionel Sambuc  *	-- Arnold Robbins
1885fee539SLionel Sambuc  *
1985fee539SLionel Sambuc  *	Redone as a library that can replace open, read, write, etc, by
2085fee539SLionel Sambuc  *	Fred Fish, with some additional work by Arnold Robbins.
2185fee539SLionel Sambuc  */
2285fee539SLionel Sambuc 
2385fee539SLionel Sambuc /*
2485fee539SLionel Sambuc  *	MAXUNIT --- Maximum number of remote tape file units
2585fee539SLionel Sambuc  *
2685fee539SLionel Sambuc  *	READ --- Return the number of the read side file descriptor
2785fee539SLionel Sambuc  *	WRITE --- Return the number of the write side file descriptor
2885fee539SLionel Sambuc  */
2985fee539SLionel Sambuc 
3085fee539SLionel Sambuc #include <sys/cdefs.h>
3185fee539SLionel Sambuc __RCSID("$NetBSD: rmtlib.c,v 1.26 2012/03/21 10:10:37 matt Exp $");
3285fee539SLionel Sambuc 
3385fee539SLionel Sambuc #define RMTIOCTL	1
3485fee539SLionel Sambuc /* #define USE_REXEC	1 */	/* rexec code courtesy of Dan Kegel, srs!dan */
3585fee539SLionel Sambuc 
3685fee539SLionel Sambuc #include <sys/types.h>
3785fee539SLionel Sambuc #include <sys/stat.h>
3885fee539SLionel Sambuc 
3985fee539SLionel Sambuc #ifdef RMTIOCTL
4085fee539SLionel Sambuc #include <sys/ioctl.h>
4185fee539SLionel Sambuc #include <sys/mtio.h>
4285fee539SLionel Sambuc #endif
4385fee539SLionel Sambuc 
4485fee539SLionel Sambuc #include <assert.h>
4585fee539SLionel Sambuc #include <errno.h>
4685fee539SLionel Sambuc #include <fcntl.h>
4785fee539SLionel Sambuc #include <signal.h>
4885fee539SLionel Sambuc #include <stdarg.h>
4985fee539SLionel Sambuc #include <stdio.h>
5085fee539SLionel Sambuc #include <stdlib.h>
5185fee539SLionel Sambuc #include <string.h>
5285fee539SLionel Sambuc #include <unistd.h>
5385fee539SLionel Sambuc #include <err.h>
5485fee539SLionel Sambuc 
5585fee539SLionel Sambuc #ifdef USE_REXEC
5685fee539SLionel Sambuc #include <netdb.h>
5785fee539SLionel Sambuc #endif
5885fee539SLionel Sambuc 
5985fee539SLionel Sambuc #define __RMTLIB_PRIVATE
6085fee539SLionel Sambuc #include <rmt.h>		/* get prototypes for remapped functions */
6185fee539SLionel Sambuc 
6285fee539SLionel Sambuc #include "pathnames.h"
6385fee539SLionel Sambuc 
6485fee539SLionel Sambuc static	int	_rmt_close(int);
6585fee539SLionel Sambuc static	int	_rmt_ioctl(int, unsigned long, void *);
6685fee539SLionel Sambuc static	off_t	_rmt_lseek(int, off_t, int);
6785fee539SLionel Sambuc static	int	_rmt_open(const char *, int, int);
6885fee539SLionel Sambuc static	ssize_t	_rmt_read(int, void *, size_t);
6985fee539SLionel Sambuc static	ssize_t	_rmt_write(int, const void *, size_t);
7085fee539SLionel Sambuc static	int	command(int, const char *);
7185fee539SLionel Sambuc static	int	remdev(const char *);
7285fee539SLionel Sambuc static	void	rmtabort(int);
7385fee539SLionel Sambuc static	int	status(int);
7485fee539SLionel Sambuc 
7585fee539SLionel Sambuc 
7685fee539SLionel Sambuc #define BUFMAGIC	64	/* a magic number for buffer sizes */
7785fee539SLionel Sambuc #define MAXUNIT		4
7885fee539SLionel Sambuc 
7985fee539SLionel Sambuc #define READ(fd)	(Ctp[fd][0])
8085fee539SLionel Sambuc #define WRITE(fd)	(Ptc[fd][1])
8185fee539SLionel Sambuc 
8285fee539SLionel Sambuc static int Ctp[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
8385fee539SLionel Sambuc static int Ptc[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
8485fee539SLionel Sambuc 
8585fee539SLionel Sambuc 
8685fee539SLionel Sambuc /*
8785fee539SLionel Sambuc  *	rmtabort --- close off a remote tape connection
8885fee539SLionel Sambuc  */
8985fee539SLionel Sambuc static void
rmtabort(int fildes)9085fee539SLionel Sambuc rmtabort(int fildes)
9185fee539SLionel Sambuc {
9285fee539SLionel Sambuc 
9385fee539SLionel Sambuc 	close(READ(fildes));
9485fee539SLionel Sambuc 	close(WRITE(fildes));
9585fee539SLionel Sambuc 	READ(fildes) = -1;
9685fee539SLionel Sambuc 	WRITE(fildes) = -1;
9785fee539SLionel Sambuc }
9885fee539SLionel Sambuc 
9985fee539SLionel Sambuc 
10085fee539SLionel Sambuc /*
10185fee539SLionel Sambuc  *	command --- attempt to perform a remote tape command
10285fee539SLionel Sambuc  */
10385fee539SLionel Sambuc static int
command(int fildes,const char * buf)10485fee539SLionel Sambuc command(int fildes, const char *buf)
10585fee539SLionel Sambuc {
10685fee539SLionel Sambuc 	size_t blen;
10785fee539SLionel Sambuc 	sig_t pstat;
10885fee539SLionel Sambuc 
10985fee539SLionel Sambuc 	_DIAGASSERT(buf != NULL);
11085fee539SLionel Sambuc 
11185fee539SLionel Sambuc /*
11285fee539SLionel Sambuc  *	save current pipe status and try to make the request
11385fee539SLionel Sambuc  */
11485fee539SLionel Sambuc 
11585fee539SLionel Sambuc 	blen = strlen(buf);
11685fee539SLionel Sambuc 	pstat = signal(SIGPIPE, SIG_IGN);
11785fee539SLionel Sambuc 	if ((size_t)write(WRITE(fildes), buf, blen) == blen) {
11885fee539SLionel Sambuc 		signal(SIGPIPE, pstat);
11985fee539SLionel Sambuc 		return 0;
12085fee539SLionel Sambuc 	}
12185fee539SLionel Sambuc 
12285fee539SLionel Sambuc /*
12385fee539SLionel Sambuc  *	something went wrong. close down and go home
12485fee539SLionel Sambuc  */
12585fee539SLionel Sambuc 
12685fee539SLionel Sambuc 	signal(SIGPIPE, pstat);
12785fee539SLionel Sambuc 	rmtabort(fildes);
12885fee539SLionel Sambuc 
12985fee539SLionel Sambuc 	errno = EIO;
13085fee539SLionel Sambuc 	return -1;
13185fee539SLionel Sambuc }
13285fee539SLionel Sambuc 
13385fee539SLionel Sambuc 
13485fee539SLionel Sambuc /*
13585fee539SLionel Sambuc  *	status --- retrieve the status from the pipe
13685fee539SLionel Sambuc  */
13785fee539SLionel Sambuc static int
status(int fildes)13885fee539SLionel Sambuc status(int fildes)
13985fee539SLionel Sambuc {
14085fee539SLionel Sambuc 	int i;
14185fee539SLionel Sambuc 	char c, *cp;
14285fee539SLionel Sambuc 	char buffer[BUFMAGIC];
14385fee539SLionel Sambuc 
14485fee539SLionel Sambuc /*
14585fee539SLionel Sambuc  *	read the reply command line
14685fee539SLionel Sambuc  */
14785fee539SLionel Sambuc 
14885fee539SLionel Sambuc 	for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++) {
14985fee539SLionel Sambuc 		if (read(READ(fildes), cp, 1) != 1) {
15085fee539SLionel Sambuc 			rmtabort(fildes);
15185fee539SLionel Sambuc 			errno = EIO;
15285fee539SLionel Sambuc 			return -1;
15385fee539SLionel Sambuc 		}
15485fee539SLionel Sambuc 		if (*cp == '\n') {
15585fee539SLionel Sambuc 			*cp = 0;
15685fee539SLionel Sambuc 			break;
15785fee539SLionel Sambuc 		}
15885fee539SLionel Sambuc 	}
15985fee539SLionel Sambuc 
16085fee539SLionel Sambuc 	if (i == BUFMAGIC) {
16185fee539SLionel Sambuc 		rmtabort(fildes);
16285fee539SLionel Sambuc 		errno = EIO;
16385fee539SLionel Sambuc 		return -1;
16485fee539SLionel Sambuc 	}
16585fee539SLionel Sambuc 
16685fee539SLionel Sambuc /*
16785fee539SLionel Sambuc  *	check the return status
16885fee539SLionel Sambuc  */
16985fee539SLionel Sambuc 
17085fee539SLionel Sambuc 	for (cp = buffer; *cp; cp++)
17185fee539SLionel Sambuc 		if (*cp != ' ')
17285fee539SLionel Sambuc 			break;
17385fee539SLionel Sambuc 
17485fee539SLionel Sambuc 	if (*cp == 'E' || *cp == 'F') {
17585fee539SLionel Sambuc 		errno = atoi(cp + 1);
17685fee539SLionel Sambuc 		while (read(READ(fildes), &c, 1) == 1)
17785fee539SLionel Sambuc 			if (c == '\n')
17885fee539SLionel Sambuc 				break;
17985fee539SLionel Sambuc 
18085fee539SLionel Sambuc 		if (*cp == 'F')
18185fee539SLionel Sambuc 			rmtabort(fildes);
18285fee539SLionel Sambuc 
18385fee539SLionel Sambuc 		return -1;
18485fee539SLionel Sambuc 	}
18585fee539SLionel Sambuc 
18685fee539SLionel Sambuc /*
18785fee539SLionel Sambuc  *	check for mis-synced pipes
18885fee539SLionel Sambuc  */
18985fee539SLionel Sambuc 
19085fee539SLionel Sambuc 	if (*cp != 'A') {
19185fee539SLionel Sambuc 		rmtabort(fildes);
19285fee539SLionel Sambuc 		errno = EIO;
19385fee539SLionel Sambuc 		return -1;
19485fee539SLionel Sambuc 	}
19585fee539SLionel Sambuc 
19685fee539SLionel Sambuc 	return atoi(cp + 1);
19785fee539SLionel Sambuc }
19885fee539SLionel Sambuc 
19985fee539SLionel Sambuc 
20085fee539SLionel Sambuc #ifdef USE_REXEC
20185fee539SLionel Sambuc /*
20285fee539SLionel Sambuc  * _rmt_rexec
20385fee539SLionel Sambuc  *
20485fee539SLionel Sambuc  * execute /etc/rmt on a remote system using rexec().
20585fee539SLionel Sambuc  * Return file descriptor of bidirectional socket for stdin and stdout
20685fee539SLionel Sambuc  * If username is NULL, or an empty string, uses current username.
20785fee539SLionel Sambuc  *
20885fee539SLionel Sambuc  * ADR: By default, this code is not used, since it requires that
20985fee539SLionel Sambuc  * the user have a .netrc file in his/her home directory, or that the
21085fee539SLionel Sambuc  * application designer be willing to have rexec prompt for login and
21185fee539SLionel Sambuc  * password info. This may be unacceptable, and .rhosts files for use
21285fee539SLionel Sambuc  * with rsh are much more common on BSD systems.
21385fee539SLionel Sambuc  */
21485fee539SLionel Sambuc 
21585fee539SLionel Sambuc static	int	_rmt_rexec(const char *, const char *);
21685fee539SLionel Sambuc 
21785fee539SLionel Sambuc static int
_rmt_rexec(const char * host,const char * user)21885fee539SLionel Sambuc _rmt_rexec(const char *host, const char *user)
21985fee539SLionel Sambuc {
22085fee539SLionel Sambuc 	struct servent *rexecserv;
22185fee539SLionel Sambuc 
22285fee539SLionel Sambuc 	_DIAGASSERT(host != NULL);
22385fee539SLionel Sambuc 	/* user may be NULL */
22485fee539SLionel Sambuc 
22585fee539SLionel Sambuc 	rexecserv = getservbyname("exec", "tcp");
22685fee539SLionel Sambuc 	if (rexecserv == NULL)
22785fee539SLionel Sambuc 		errx(1, "exec/tcp: service not available.");
22885fee539SLionel Sambuc 	if ((user != NULL) && *user == '\0')
22985fee539SLionel Sambuc 		user = NULL;
23085fee539SLionel Sambuc 	return rexec(&host, rexecserv->s_port, user, NULL,
23185fee539SLionel Sambuc 	    "/etc/rmt", NULL);
23285fee539SLionel Sambuc }
23385fee539SLionel Sambuc #endif /* USE_REXEC */
23485fee539SLionel Sambuc 
23585fee539SLionel Sambuc 
23685fee539SLionel Sambuc /*
23785fee539SLionel Sambuc  *	_rmt_open --- open a magtape device on system specified, as given user
23885fee539SLionel Sambuc  *
23985fee539SLionel Sambuc  *	file name has the form [user@]system:/dev/????
24085fee539SLionel Sambuc #ifdef COMPAT
24185fee539SLionel Sambuc  *	file name has the form system[.user]:/dev/????
24285fee539SLionel Sambuc #endif
24385fee539SLionel Sambuc  */
24485fee539SLionel Sambuc 
24585fee539SLionel Sambuc #define MAXHOSTLEN	257	/* BSD allows very long host names... */
24685fee539SLionel Sambuc 
24785fee539SLionel Sambuc static int
24885fee539SLionel Sambuc /*ARGSUSED*/
_rmt_open(const char * path,int oflag,int mode)24985fee539SLionel Sambuc _rmt_open(const char *path, int oflag, int mode)
25085fee539SLionel Sambuc {
25185fee539SLionel Sambuc 	int i;
25285fee539SLionel Sambuc 	char buffer[BUFMAGIC];
25385fee539SLionel Sambuc 	char host[MAXHOSTLEN];
25485fee539SLionel Sambuc 	char device[BUFMAGIC];
25585fee539SLionel Sambuc 	char login[BUFMAGIC];
25685fee539SLionel Sambuc 	char *sys, *dev, *user;
25785fee539SLionel Sambuc 	const char *rshpath, *rsh;
25885fee539SLionel Sambuc 
25985fee539SLionel Sambuc 	_DIAGASSERT(path != NULL);
26085fee539SLionel Sambuc 
26185fee539SLionel Sambuc 	sys = host;
26285fee539SLionel Sambuc 	dev = device;
26385fee539SLionel Sambuc 	user = login;
26485fee539SLionel Sambuc 
26585fee539SLionel Sambuc /*
26685fee539SLionel Sambuc  *	first, find an open pair of file descriptors
26785fee539SLionel Sambuc  */
26885fee539SLionel Sambuc 
26985fee539SLionel Sambuc 	for (i = 0; i < MAXUNIT; i++)
27085fee539SLionel Sambuc 		if (READ(i) == -1 && WRITE(i) == -1)
27185fee539SLionel Sambuc 			break;
27285fee539SLionel Sambuc 
27385fee539SLionel Sambuc 	if (i == MAXUNIT) {
27485fee539SLionel Sambuc 		errno = EMFILE;
27585fee539SLionel Sambuc 		return -1;
27685fee539SLionel Sambuc 	}
27785fee539SLionel Sambuc 
27885fee539SLionel Sambuc /*
27985fee539SLionel Sambuc  *	pull apart system and device, and optional user
28085fee539SLionel Sambuc  *	don't munge original string
28185fee539SLionel Sambuc  *	if COMPAT is defined, also handle old (4.2) style person.site notation.
28285fee539SLionel Sambuc  */
28385fee539SLionel Sambuc 
28485fee539SLionel Sambuc 	while (*path != '@'
28585fee539SLionel Sambuc #ifdef COMPAT
28685fee539SLionel Sambuc 			&& *path != '.'
28785fee539SLionel Sambuc #endif
28885fee539SLionel Sambuc 			&& *path != ':') {
28985fee539SLionel Sambuc 		*sys++ = *path++;
29085fee539SLionel Sambuc 	}
29185fee539SLionel Sambuc 	*sys = '\0';
29285fee539SLionel Sambuc 	path++;
29385fee539SLionel Sambuc 
29485fee539SLionel Sambuc 	if (*(path - 1) == '@') {
29585fee539SLionel Sambuc 		(void)strncpy(user, host, sizeof(login) - 1);
29685fee539SLionel Sambuc 				/* saw user part of user@host */
29785fee539SLionel Sambuc 		sys = host;			/* start over */
29885fee539SLionel Sambuc 		while (*path != ':') {
29985fee539SLionel Sambuc 			*sys++ = *path++;
30085fee539SLionel Sambuc 		}
30185fee539SLionel Sambuc 		*sys = '\0';
30285fee539SLionel Sambuc 		path++;
30385fee539SLionel Sambuc 	}
30485fee539SLionel Sambuc #ifdef COMPAT
30585fee539SLionel Sambuc 	else if (*(path - 1) == '.') {
30685fee539SLionel Sambuc 		while (*path != ':') {
30785fee539SLionel Sambuc 			*user++ = *path++;
30885fee539SLionel Sambuc 		}
30985fee539SLionel Sambuc 		*user = '\0';
31085fee539SLionel Sambuc 		path++;
31185fee539SLionel Sambuc 	}
31285fee539SLionel Sambuc #endif
31385fee539SLionel Sambuc 	else
31485fee539SLionel Sambuc 		*user = '\0';
31585fee539SLionel Sambuc 
31685fee539SLionel Sambuc 	while (*path) {
31785fee539SLionel Sambuc 		*dev++ = *path++;
31885fee539SLionel Sambuc 	}
31985fee539SLionel Sambuc 	*dev = '\0';
32085fee539SLionel Sambuc 
32185fee539SLionel Sambuc #ifdef USE_REXEC
32285fee539SLionel Sambuc /*
32385fee539SLionel Sambuc  *	Execute the remote command using rexec
32485fee539SLionel Sambuc  */
32585fee539SLionel Sambuc 	READ(i) = WRITE(i) = _rmt_rexec(host, login);
32685fee539SLionel Sambuc 	if (READ(i) < 0)
32785fee539SLionel Sambuc 		return -1;
32885fee539SLionel Sambuc #else
32985fee539SLionel Sambuc /*
33085fee539SLionel Sambuc  *	setup the pipes for the 'rsh' command and fork
33185fee539SLionel Sambuc  */
33285fee539SLionel Sambuc 
33385fee539SLionel Sambuc 	if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
33485fee539SLionel Sambuc 		return -1;
33585fee539SLionel Sambuc 
33685fee539SLionel Sambuc 	switch (fork()) {
33785fee539SLionel Sambuc 	case -1:
33885fee539SLionel Sambuc 		return -1;
33985fee539SLionel Sambuc 
34085fee539SLionel Sambuc 	case 0:
34185fee539SLionel Sambuc 		close(0);
34285fee539SLionel Sambuc 		dup(Ptc[i][0]);
34385fee539SLionel Sambuc 		close(Ptc[i][0]); close(Ptc[i][1]);
34485fee539SLionel Sambuc 		close(1);
34585fee539SLionel Sambuc 		dup(Ctp[i][1]);
34685fee539SLionel Sambuc 		close(Ctp[i][0]); close(Ctp[i][1]);
34785fee539SLionel Sambuc 		(void) setuid(getuid());
34885fee539SLionel Sambuc 		(void) setgid(getgid());
34985fee539SLionel Sambuc 
35085fee539SLionel Sambuc 		if ((rshpath = getenv("RCMD_CMD")) == NULL)
35185fee539SLionel Sambuc 			rshpath = _PATH_RSH;
35285fee539SLionel Sambuc 		if ((rsh = strrchr(rshpath, '/')) == NULL)
35385fee539SLionel Sambuc 			rsh = rshpath;
35485fee539SLionel Sambuc 		else
35585fee539SLionel Sambuc 			rsh++;
35685fee539SLionel Sambuc 
35785fee539SLionel Sambuc 		if (*login) {
35885fee539SLionel Sambuc 			execl(rshpath, rsh, host, "-l", login, _PATH_RMT, NULL);
35985fee539SLionel Sambuc 		} else {
36085fee539SLionel Sambuc 			execl(rshpath, rsh, host, _PATH_RMT, NULL);
36185fee539SLionel Sambuc 		}
36285fee539SLionel Sambuc 
36385fee539SLionel Sambuc /*
36485fee539SLionel Sambuc  *	bad problems if we get here
36585fee539SLionel Sambuc  */
36685fee539SLionel Sambuc 
36785fee539SLionel Sambuc 		err(1, "Cannnot exec %s", rshpath);
36885fee539SLionel Sambuc 		/*FALLTHROUGH*/
36985fee539SLionel Sambuc 	default:
37085fee539SLionel Sambuc 		break;
37185fee539SLionel Sambuc 	}
37285fee539SLionel Sambuc 
37385fee539SLionel Sambuc 	close(Ptc[i][0]); close(Ctp[i][1]);
37485fee539SLionel Sambuc #endif
37585fee539SLionel Sambuc 
37685fee539SLionel Sambuc /*
37785fee539SLionel Sambuc  *	now attempt to open the tape device
37885fee539SLionel Sambuc  */
37985fee539SLionel Sambuc 
38085fee539SLionel Sambuc 	(void)snprintf(buffer, sizeof(buffer), "O%s\n%d\n", device, oflag);
38185fee539SLionel Sambuc 	if (command(i, buffer) == -1 || status(i) == -1)
38285fee539SLionel Sambuc 		return -1;
38385fee539SLionel Sambuc 
38485fee539SLionel Sambuc 	return i;
38585fee539SLionel Sambuc }
38685fee539SLionel Sambuc 
38785fee539SLionel Sambuc 
38885fee539SLionel Sambuc /*
38985fee539SLionel Sambuc  *	_rmt_close --- close a remote magtape unit and shut down
39085fee539SLionel Sambuc  */
39185fee539SLionel Sambuc static int
_rmt_close(int fildes)39285fee539SLionel Sambuc _rmt_close(int fildes)
39385fee539SLionel Sambuc {
39485fee539SLionel Sambuc 	int rc;
39585fee539SLionel Sambuc 
39685fee539SLionel Sambuc 	if (command(fildes, "C\n") != -1) {
39785fee539SLionel Sambuc 		rc = status(fildes);
39885fee539SLionel Sambuc 
39985fee539SLionel Sambuc 		rmtabort(fildes);
40085fee539SLionel Sambuc 		return rc;
40185fee539SLionel Sambuc 	}
40285fee539SLionel Sambuc 
40385fee539SLionel Sambuc 	return -1;
40485fee539SLionel Sambuc }
40585fee539SLionel Sambuc 
40685fee539SLionel Sambuc 
40785fee539SLionel Sambuc /*
40885fee539SLionel Sambuc  *	_rmt_read --- read a buffer from a remote tape
40985fee539SLionel Sambuc  */
41085fee539SLionel Sambuc static ssize_t
_rmt_read(int fildes,void * buf,size_t nbyte)41185fee539SLionel Sambuc _rmt_read(int fildes, void *buf, size_t nbyte)
41285fee539SLionel Sambuc {
41385fee539SLionel Sambuc 	size_t rc;
41485fee539SLionel Sambuc 	int rv;
41585fee539SLionel Sambuc 	ssize_t nread;
41685fee539SLionel Sambuc 	char *p;
41785fee539SLionel Sambuc 	char buffer[BUFMAGIC];
41885fee539SLionel Sambuc 
41985fee539SLionel Sambuc 	_DIAGASSERT(buf != NULL);
42085fee539SLionel Sambuc 
42185fee539SLionel Sambuc 	(void)snprintf(buffer, sizeof buffer, "R%zu\n", nbyte);
42285fee539SLionel Sambuc 	if (command(fildes, buffer) == -1 || (rv = status(fildes)) == -1)
42385fee539SLionel Sambuc 		return -1;
42485fee539SLionel Sambuc 
42585fee539SLionel Sambuc 	if (rv > (int)nbyte)
42685fee539SLionel Sambuc 		rv = (int)nbyte;
42785fee539SLionel Sambuc 
42885fee539SLionel Sambuc 	for (rc = rv, p = buf; rc > 0; rc -= nread, p += nread) {
42985fee539SLionel Sambuc 		if ((nread = read(READ(fildes), p, rc)) <= 0) {
43085fee539SLionel Sambuc 			rmtabort(fildes);
43185fee539SLionel Sambuc 			errno = EIO;
43285fee539SLionel Sambuc 			return -1;
43385fee539SLionel Sambuc 		}
43485fee539SLionel Sambuc 	}
43585fee539SLionel Sambuc 
43685fee539SLionel Sambuc 	return rv;
43785fee539SLionel Sambuc }
43885fee539SLionel Sambuc 
43985fee539SLionel Sambuc 
44085fee539SLionel Sambuc /*
44185fee539SLionel Sambuc  *	_rmt_write --- write a buffer to the remote tape
44285fee539SLionel Sambuc  */
44385fee539SLionel Sambuc static ssize_t
_rmt_write(int fildes,const void * buf,size_t nbyte)44485fee539SLionel Sambuc _rmt_write(int fildes, const void *buf, size_t nbyte)
44585fee539SLionel Sambuc {
44685fee539SLionel Sambuc 	char buffer[BUFMAGIC];
44785fee539SLionel Sambuc 	sig_t pstat;
44885fee539SLionel Sambuc 
44985fee539SLionel Sambuc 	_DIAGASSERT(buf != NULL);
45085fee539SLionel Sambuc 
45185fee539SLionel Sambuc 	(void)snprintf(buffer, sizeof buffer, "W%zu\n", nbyte);
45285fee539SLionel Sambuc 	if (command(fildes, buffer) == -1)
45385fee539SLionel Sambuc 		return -1;
45485fee539SLionel Sambuc 
45585fee539SLionel Sambuc 	pstat = signal(SIGPIPE, SIG_IGN);
456*0a6a1f1dSLionel Sambuc 	if ((size_t)write(WRITE(fildes), buf, nbyte) == nbyte) {
45785fee539SLionel Sambuc 		signal(SIGPIPE, pstat);
45885fee539SLionel Sambuc 		return status(fildes);
45985fee539SLionel Sambuc 	}
46085fee539SLionel Sambuc 
46185fee539SLionel Sambuc 	signal(SIGPIPE, pstat);
46285fee539SLionel Sambuc 	rmtabort(fildes);
46385fee539SLionel Sambuc 	errno = EIO;
46485fee539SLionel Sambuc 	return -1;
46585fee539SLionel Sambuc }
46685fee539SLionel Sambuc 
46785fee539SLionel Sambuc 
46885fee539SLionel Sambuc /*
46985fee539SLionel Sambuc  *	_rmt_lseek --- perform an imitation lseek operation remotely
47085fee539SLionel Sambuc  */
47185fee539SLionel Sambuc static off_t
_rmt_lseek(int fildes,off_t offset,int whence)47285fee539SLionel Sambuc _rmt_lseek(int fildes, off_t offset, int whence)
47385fee539SLionel Sambuc {
47485fee539SLionel Sambuc 	char buffer[BUFMAGIC];
47585fee539SLionel Sambuc 
47685fee539SLionel Sambuc 	/*LONGLONG*/
47785fee539SLionel Sambuc 	(void)snprintf(buffer, sizeof buffer, "L%lld\n%d\n", (long long)offset,
47885fee539SLionel Sambuc 	    whence);
47985fee539SLionel Sambuc 	if (command(fildes, buffer) == -1)
48085fee539SLionel Sambuc 		return -1;
48185fee539SLionel Sambuc 
48285fee539SLionel Sambuc 	return status(fildes);
48385fee539SLionel Sambuc }
48485fee539SLionel Sambuc 
48585fee539SLionel Sambuc 
48685fee539SLionel Sambuc /*
48785fee539SLionel Sambuc  *	_rmt_ioctl --- perform raw tape operations remotely
48885fee539SLionel Sambuc  */
48985fee539SLionel Sambuc #ifdef RMTIOCTL
49085fee539SLionel Sambuc static int
_rmt_ioctl(int fildes,unsigned long op,void * arg)49185fee539SLionel Sambuc _rmt_ioctl(int fildes, unsigned long op, void *arg)
49285fee539SLionel Sambuc {
49385fee539SLionel Sambuc 	char c;
49485fee539SLionel Sambuc 	int rv;
49585fee539SLionel Sambuc 	size_t rc;
49685fee539SLionel Sambuc 	ssize_t cnt;
49785fee539SLionel Sambuc 	char buffer[BUFMAGIC], *p;
49885fee539SLionel Sambuc 	struct mtop *mtop = arg;
49985fee539SLionel Sambuc 
50085fee539SLionel Sambuc 	_DIAGASSERT(arg != NULL);
50185fee539SLionel Sambuc 
50285fee539SLionel Sambuc /*
50385fee539SLionel Sambuc  *	MTIOCOP is the easy one. nothing is transfered in binary
50485fee539SLionel Sambuc  */
50585fee539SLionel Sambuc 
50685fee539SLionel Sambuc 	if (op == MTIOCTOP) {
50785fee539SLionel Sambuc 		(void)snprintf(buffer, sizeof buffer, "I%d\n%d\n",
50885fee539SLionel Sambuc 		    mtop->mt_op, mtop->mt_count);
50985fee539SLionel Sambuc 		if (command(fildes, buffer) == -1)
51085fee539SLionel Sambuc 			return -1;
51185fee539SLionel Sambuc 		return status(fildes);
51285fee539SLionel Sambuc 	}
51385fee539SLionel Sambuc 
51485fee539SLionel Sambuc /*
51585fee539SLionel Sambuc  *	we can only handle 2 ops, if not the other one, punt
51685fee539SLionel Sambuc  */
51785fee539SLionel Sambuc 
51885fee539SLionel Sambuc 	if (op != MTIOCGET) {
51985fee539SLionel Sambuc 		errno = EINVAL;
52085fee539SLionel Sambuc 		return -1;
52185fee539SLionel Sambuc 	}
52285fee539SLionel Sambuc 
52385fee539SLionel Sambuc /*
52485fee539SLionel Sambuc  *	grab the status and read it directly into the structure
52585fee539SLionel Sambuc  *	this assumes that the status buffer is (hopefully) not
52685fee539SLionel Sambuc  *	padded and that 2 shorts fit in a long without any word
52785fee539SLionel Sambuc  *	alignment problems, ie - the whole struct is contiguous
52885fee539SLionel Sambuc  *	NOTE - this is probably NOT a good assumption.
52985fee539SLionel Sambuc  */
53085fee539SLionel Sambuc 
53185fee539SLionel Sambuc 	if (command(fildes, "S") == -1 || (rv = status(fildes)) == -1)
53285fee539SLionel Sambuc 		return -1;
53385fee539SLionel Sambuc 
53485fee539SLionel Sambuc 	memset(arg, 0, sizeof(struct mtget));
53585fee539SLionel Sambuc 	for (rc = rv, p = arg; rc > 0; rc -= cnt, p += cnt) {
53685fee539SLionel Sambuc 		if ((cnt = read(READ(fildes), p, rc)) <= 0) {
53785fee539SLionel Sambuc 			rmtabort(fildes);
53885fee539SLionel Sambuc 			errno = EIO;
53985fee539SLionel Sambuc 			return -1;
54085fee539SLionel Sambuc 		}
54185fee539SLionel Sambuc 	}
54285fee539SLionel Sambuc 
54385fee539SLionel Sambuc /*
54485fee539SLionel Sambuc  *	now we check for byte position. mt_type is a small integer field
54585fee539SLionel Sambuc  *	(normally) so we will check its magnitude. if it is larger than
54685fee539SLionel Sambuc  *	256, we will assume that the bytes are swapped and go through
54785fee539SLionel Sambuc  *	and reverse all the bytes
54885fee539SLionel Sambuc  */
54985fee539SLionel Sambuc 
55085fee539SLionel Sambuc 	if (((struct mtget *)(void *)p)->mt_type < 256)
55185fee539SLionel Sambuc 		return 0;
55285fee539SLionel Sambuc 
55385fee539SLionel Sambuc 	for (cnt = 0; cnt < rv; cnt += 2) {
55485fee539SLionel Sambuc 		c = p[cnt];
55585fee539SLionel Sambuc 		p[cnt] = p[cnt + 1];
55685fee539SLionel Sambuc 		p[cnt + 1] = c;
55785fee539SLionel Sambuc 	}
55885fee539SLionel Sambuc 
55985fee539SLionel Sambuc 	return 0;
56085fee539SLionel Sambuc }
56185fee539SLionel Sambuc #endif /* RMTIOCTL */
56285fee539SLionel Sambuc 
56385fee539SLionel Sambuc 
56485fee539SLionel Sambuc /*
56585fee539SLionel Sambuc  *	Added routines to replace open(), close(), lseek(), ioctl(), etc.
56685fee539SLionel Sambuc  *	The preprocessor can be used to remap these the rmtopen(), etc
56785fee539SLionel Sambuc  *	thus minimizing source changes:
56885fee539SLionel Sambuc  *
56985fee539SLionel Sambuc  *		#ifdef <something>
57085fee539SLionel Sambuc  *		#  define access rmtaccess
57185fee539SLionel Sambuc  *		#  define close rmtclose
57285fee539SLionel Sambuc  *		#  define creat rmtcreat
57385fee539SLionel Sambuc  *		#  define dup rmtdup
57485fee539SLionel Sambuc  *		#  define fcntl rmtfcntl
57585fee539SLionel Sambuc  *		#  define fstat rmtfstat
57685fee539SLionel Sambuc  *		#  define ioctl rmtioctl
57785fee539SLionel Sambuc  *		#  define isatty rmtisatty
57885fee539SLionel Sambuc  *		#  define lseek rmtlseek
57985fee539SLionel Sambuc  *		#  define lstat rmtlstat
58085fee539SLionel Sambuc  *		#  define open rmtopen
58185fee539SLionel Sambuc  *		#  define read rmtread
58285fee539SLionel Sambuc  *		#  define stat rmtstat
58385fee539SLionel Sambuc  *		#  define write rmtwrite
58485fee539SLionel Sambuc  *		#endif
58585fee539SLionel Sambuc  *
58685fee539SLionel Sambuc  *	-- Fred Fish
58785fee539SLionel Sambuc  *
58885fee539SLionel Sambuc  *	ADR --- I set up a <rmt.h> include file for this
58985fee539SLionel Sambuc  *
59085fee539SLionel Sambuc  */
59185fee539SLionel Sambuc 
59285fee539SLionel Sambuc /*
59385fee539SLionel Sambuc  *	Note that local vs remote file descriptors are distinquished
59485fee539SLionel Sambuc  *	by adding a bias to the remote descriptors.  This is a quick
59585fee539SLionel Sambuc  *	and dirty trick that may not be portable to some systems.
59685fee539SLionel Sambuc  */
59785fee539SLionel Sambuc 
59885fee539SLionel Sambuc #define REM_BIAS 128
59985fee539SLionel Sambuc 
60085fee539SLionel Sambuc 
60185fee539SLionel Sambuc /*
60285fee539SLionel Sambuc  *	Test pathname to see if it is local or remote.  A remote device
60385fee539SLionel Sambuc  *	is any string that contains ":/dev/".  Returns 1 if remote,
60485fee539SLionel Sambuc  *	0 otherwise.
60585fee539SLionel Sambuc  */
60685fee539SLionel Sambuc 
60785fee539SLionel Sambuc static int
remdev(const char * path)60885fee539SLionel Sambuc remdev(const char *path)
60985fee539SLionel Sambuc {
61085fee539SLionel Sambuc 
61185fee539SLionel Sambuc 	_DIAGASSERT(path != NULL);
61285fee539SLionel Sambuc 
61385fee539SLionel Sambuc 	if ((path = strchr(path, ':')) != NULL) {
61485fee539SLionel Sambuc 		if (strncmp(path + 1, "/dev/", 5) == 0) {
61585fee539SLionel Sambuc 			return 1;
61685fee539SLionel Sambuc 		}
61785fee539SLionel Sambuc 	}
61885fee539SLionel Sambuc 	return 0;
61985fee539SLionel Sambuc }
62085fee539SLionel Sambuc 
62185fee539SLionel Sambuc 
62285fee539SLionel Sambuc /*
62385fee539SLionel Sambuc  *	Open a local or remote file.  Looks just like open(2) to
62485fee539SLionel Sambuc  *	caller.
62585fee539SLionel Sambuc  */
62685fee539SLionel Sambuc int
rmtopen(const char * path,int oflag,...)62785fee539SLionel Sambuc rmtopen(const char *path, int oflag, ...)
62885fee539SLionel Sambuc {
62984d9c625SLionel Sambuc 	mode_t mode;
63085fee539SLionel Sambuc 	int fd;
63185fee539SLionel Sambuc 	va_list ap;
63285fee539SLionel Sambuc 	va_start(ap, oflag);
63385fee539SLionel Sambuc 
63484d9c625SLionel Sambuc 	mode = va_arg(ap, mode_t);
63585fee539SLionel Sambuc 	va_end(ap);
63685fee539SLionel Sambuc 
63785fee539SLionel Sambuc 	_DIAGASSERT(path != NULL);
63885fee539SLionel Sambuc 
63985fee539SLionel Sambuc 	if (remdev(path)) {
64085fee539SLionel Sambuc 		fd = _rmt_open(path, oflag, (int)mode);
64185fee539SLionel Sambuc 
64285fee539SLionel Sambuc 		return (fd == -1) ? -1 : (fd + REM_BIAS);
64385fee539SLionel Sambuc 	} else {
64485fee539SLionel Sambuc 		return open(path, oflag, mode);
64585fee539SLionel Sambuc 	}
64685fee539SLionel Sambuc }
64785fee539SLionel Sambuc 
64885fee539SLionel Sambuc /*
64985fee539SLionel Sambuc  *	Test pathname for specified access.  Looks just like access(2)
65085fee539SLionel Sambuc  *	to caller.
65185fee539SLionel Sambuc  */
65285fee539SLionel Sambuc 
65385fee539SLionel Sambuc int
rmtaccess(const char * path,int amode)65485fee539SLionel Sambuc rmtaccess(const char *path, int amode)
65585fee539SLionel Sambuc {
65685fee539SLionel Sambuc 
65785fee539SLionel Sambuc 	_DIAGASSERT(path != NULL);
65885fee539SLionel Sambuc 
65985fee539SLionel Sambuc 	if (remdev(path)) {
66085fee539SLionel Sambuc 		return 0;		/* Let /etc/rmt find out */
66185fee539SLionel Sambuc 	} else {
66285fee539SLionel Sambuc 		return access(path, amode);
66385fee539SLionel Sambuc 	}
66485fee539SLionel Sambuc }
66585fee539SLionel Sambuc 
66685fee539SLionel Sambuc 
66785fee539SLionel Sambuc /*
66885fee539SLionel Sambuc  *	Isrmt. Let a programmer know he has a remote device.
66985fee539SLionel Sambuc  */
67085fee539SLionel Sambuc int
isrmt(int fd)67185fee539SLionel Sambuc isrmt(int fd)
67285fee539SLionel Sambuc {
67385fee539SLionel Sambuc 	int unbias = fd - REM_BIAS;
67485fee539SLionel Sambuc 
67585fee539SLionel Sambuc 	return (fd >= REM_BIAS) && unbias < MAXUNIT &&
67685fee539SLionel Sambuc 	    (WRITE(unbias) != -1 || READ(unbias) != -1);
67785fee539SLionel Sambuc }
67885fee539SLionel Sambuc 
67985fee539SLionel Sambuc 
68085fee539SLionel Sambuc /*
68185fee539SLionel Sambuc  *	Read from stream.  Looks just like read(2) to caller.
68285fee539SLionel Sambuc  */
68385fee539SLionel Sambuc ssize_t
rmtread(int fildes,void * buf,size_t nbyte)68485fee539SLionel Sambuc rmtread(int fildes, void *buf, size_t nbyte)
68585fee539SLionel Sambuc {
68685fee539SLionel Sambuc 
68785fee539SLionel Sambuc 	_DIAGASSERT(buf != NULL);
68885fee539SLionel Sambuc 
68985fee539SLionel Sambuc 	if (isrmt(fildes)) {
69085fee539SLionel Sambuc 		return _rmt_read(fildes - REM_BIAS, buf, nbyte);
69185fee539SLionel Sambuc 	} else {
69285fee539SLionel Sambuc 		return read(fildes, buf, nbyte);
69385fee539SLionel Sambuc 	}
69485fee539SLionel Sambuc }
69585fee539SLionel Sambuc 
69685fee539SLionel Sambuc 
69785fee539SLionel Sambuc /*
69885fee539SLionel Sambuc  *	Write to stream.  Looks just like write(2) to caller.
69985fee539SLionel Sambuc  */
70085fee539SLionel Sambuc ssize_t
rmtwrite(int fildes,const void * buf,size_t nbyte)70185fee539SLionel Sambuc rmtwrite(int fildes, const void *buf, size_t nbyte)
70285fee539SLionel Sambuc {
70385fee539SLionel Sambuc 
70485fee539SLionel Sambuc 	_DIAGASSERT(buf != NULL);
70585fee539SLionel Sambuc 
70685fee539SLionel Sambuc 	if (isrmt(fildes)) {
70785fee539SLionel Sambuc 		return _rmt_write(fildes - REM_BIAS, buf, nbyte);
70885fee539SLionel Sambuc 	} else {
70985fee539SLionel Sambuc 		return write(fildes, buf, nbyte);
71085fee539SLionel Sambuc 	}
71185fee539SLionel Sambuc }
71285fee539SLionel Sambuc 
71385fee539SLionel Sambuc /*
71485fee539SLionel Sambuc  *	Perform lseek on file.  Looks just like lseek(2) to caller.
71585fee539SLionel Sambuc  */
71685fee539SLionel Sambuc off_t
rmtlseek(int fildes,off_t offset,int whence)71785fee539SLionel Sambuc rmtlseek(int fildes, off_t offset, int whence)
71885fee539SLionel Sambuc {
71985fee539SLionel Sambuc 
72085fee539SLionel Sambuc 	if (isrmt(fildes)) {
72185fee539SLionel Sambuc 		return _rmt_lseek(fildes - REM_BIAS, offset, whence);
72285fee539SLionel Sambuc 	} else {
72385fee539SLionel Sambuc 		return lseek(fildes, offset, whence);
72485fee539SLionel Sambuc 	}
72585fee539SLionel Sambuc }
72685fee539SLionel Sambuc 
72785fee539SLionel Sambuc 
72885fee539SLionel Sambuc /*
72985fee539SLionel Sambuc  *	Close a file.  Looks just like close(2) to caller.
73085fee539SLionel Sambuc  */
73185fee539SLionel Sambuc int
rmtclose(int fildes)73285fee539SLionel Sambuc rmtclose(int fildes)
73385fee539SLionel Sambuc {
73485fee539SLionel Sambuc 
73585fee539SLionel Sambuc 	if (isrmt(fildes)) {
73685fee539SLionel Sambuc 		return _rmt_close(fildes - REM_BIAS);
73785fee539SLionel Sambuc 	} else {
73885fee539SLionel Sambuc 		return close(fildes);
73985fee539SLionel Sambuc 	}
74085fee539SLionel Sambuc }
74185fee539SLionel Sambuc 
74285fee539SLionel Sambuc 
74385fee539SLionel Sambuc /*
74485fee539SLionel Sambuc  *	Do ioctl on file.  Looks just like ioctl(2) to caller.
74585fee539SLionel Sambuc  */
74685fee539SLionel Sambuc int
rmtioctl(int fildes,unsigned long request,...)74785fee539SLionel Sambuc rmtioctl(int fildes, unsigned long request, ...)
74885fee539SLionel Sambuc {
74985fee539SLionel Sambuc 	void *arg;
75085fee539SLionel Sambuc 	va_list ap;
75185fee539SLionel Sambuc 	va_start(ap, request);
75285fee539SLionel Sambuc 
75385fee539SLionel Sambuc 	arg = va_arg(ap, void *);
75485fee539SLionel Sambuc 	va_end(ap);
75585fee539SLionel Sambuc 
75685fee539SLionel Sambuc 	/* XXX: arg may be NULL ? */
75785fee539SLionel Sambuc 
75885fee539SLionel Sambuc 	if (isrmt(fildes)) {
75985fee539SLionel Sambuc #ifdef RMTIOCTL
76085fee539SLionel Sambuc 		return _rmt_ioctl(fildes - REM_BIAS, request, arg);
76185fee539SLionel Sambuc #else
76285fee539SLionel Sambuc 		errno = EOPNOTSUPP;
76385fee539SLionel Sambuc 		return -1;		/* For now (fnf) */
76485fee539SLionel Sambuc #endif
76585fee539SLionel Sambuc 	} else {
76685fee539SLionel Sambuc 		return ioctl(fildes, request, arg);
76785fee539SLionel Sambuc 	}
76885fee539SLionel Sambuc }
76985fee539SLionel Sambuc 
77085fee539SLionel Sambuc 
77185fee539SLionel Sambuc /*
77285fee539SLionel Sambuc  *	Duplicate an open file descriptor.  Looks just like dup(2)
77385fee539SLionel Sambuc  *	to caller.
77485fee539SLionel Sambuc  */
77585fee539SLionel Sambuc int
rmtdup(int fildes)77685fee539SLionel Sambuc rmtdup(int fildes)
77785fee539SLionel Sambuc {
77885fee539SLionel Sambuc 
77985fee539SLionel Sambuc 	if (isrmt(fildes)) {
78085fee539SLionel Sambuc 		errno = EOPNOTSUPP;
78185fee539SLionel Sambuc 		return -1;		/* For now (fnf) */
78285fee539SLionel Sambuc 	} else {
78385fee539SLionel Sambuc 		return dup(fildes);
78485fee539SLionel Sambuc 	}
78585fee539SLionel Sambuc }
78685fee539SLionel Sambuc 
78785fee539SLionel Sambuc 
78885fee539SLionel Sambuc /*
78985fee539SLionel Sambuc  *	Get file status.  Looks just like fstat(2) to caller.
79085fee539SLionel Sambuc  */
79185fee539SLionel Sambuc int
rmtfstat(int fildes,struct stat * buf)79285fee539SLionel Sambuc rmtfstat(int fildes, struct stat *buf)
79385fee539SLionel Sambuc {
79485fee539SLionel Sambuc 
79585fee539SLionel Sambuc 	_DIAGASSERT(buf != NULL);
79685fee539SLionel Sambuc 
79785fee539SLionel Sambuc 	if (isrmt(fildes)) {
79885fee539SLionel Sambuc 		errno = EOPNOTSUPP;
79985fee539SLionel Sambuc 		return -1;		/* For now (fnf) */
80085fee539SLionel Sambuc 	} else {
80185fee539SLionel Sambuc 		return fstat(fildes, buf);
80285fee539SLionel Sambuc 	}
80385fee539SLionel Sambuc }
80485fee539SLionel Sambuc 
80585fee539SLionel Sambuc 
80685fee539SLionel Sambuc /*
80785fee539SLionel Sambuc  *	Get file status.  Looks just like stat(2) to caller.
80885fee539SLionel Sambuc  */
80985fee539SLionel Sambuc int
rmtstat(const char * path,struct stat * buf)81085fee539SLionel Sambuc rmtstat(const char *path, struct stat *buf)
81185fee539SLionel Sambuc {
81285fee539SLionel Sambuc 
81385fee539SLionel Sambuc 	_DIAGASSERT(path != NULL);
81485fee539SLionel Sambuc 	_DIAGASSERT(buf != NULL);
81585fee539SLionel Sambuc 
81685fee539SLionel Sambuc 	if (remdev(path)) {
81785fee539SLionel Sambuc 		errno = EOPNOTSUPP;
81885fee539SLionel Sambuc 		return -1;		/* For now (fnf) */
81985fee539SLionel Sambuc 	} else {
82085fee539SLionel Sambuc 		return stat(path, buf);
82185fee539SLionel Sambuc 	}
82285fee539SLionel Sambuc }
82385fee539SLionel Sambuc 
82485fee539SLionel Sambuc 
82585fee539SLionel Sambuc /*
82685fee539SLionel Sambuc  *	Create a file from scratch.  Looks just like creat(2) to the caller.
82785fee539SLionel Sambuc  */
82885fee539SLionel Sambuc int
rmtcreat(const char * path,mode_t mode)82985fee539SLionel Sambuc rmtcreat(const char *path, mode_t mode)
83085fee539SLionel Sambuc {
83185fee539SLionel Sambuc 
83285fee539SLionel Sambuc 	_DIAGASSERT(path != NULL);
83385fee539SLionel Sambuc 
83485fee539SLionel Sambuc 	if (remdev(path)) {
83585fee539SLionel Sambuc 		return rmtopen(path, O_WRONLY | O_CREAT, mode);
83685fee539SLionel Sambuc 	} else {
83785fee539SLionel Sambuc 		return open(path, O_CREAT | O_TRUNC | O_WRONLY, mode);
83885fee539SLionel Sambuc 	}
83985fee539SLionel Sambuc }
84085fee539SLionel Sambuc 
84185fee539SLionel Sambuc 
84285fee539SLionel Sambuc /*
84385fee539SLionel Sambuc  *	Rmtfcntl. Do a remote fcntl operation.
84485fee539SLionel Sambuc  */
84585fee539SLionel Sambuc int
rmtfcntl(int fd,int cmd,...)84685fee539SLionel Sambuc rmtfcntl(int fd, int cmd, ...)
84785fee539SLionel Sambuc {
84885fee539SLionel Sambuc 	void *arg;
84985fee539SLionel Sambuc 	va_list ap;
85085fee539SLionel Sambuc 	va_start(ap, cmd);
85185fee539SLionel Sambuc 
85285fee539SLionel Sambuc 	arg = va_arg(ap, void *);
85385fee539SLionel Sambuc 	va_end(ap);
85485fee539SLionel Sambuc 
85585fee539SLionel Sambuc 	/* XXX: arg may be NULL ? */
85685fee539SLionel Sambuc 
85785fee539SLionel Sambuc 	if (isrmt(fd)) {
85885fee539SLionel Sambuc 		errno = EOPNOTSUPP;
85985fee539SLionel Sambuc 		return -1;
86085fee539SLionel Sambuc 	} else {
86185fee539SLionel Sambuc 		return fcntl(fd, cmd, arg);
86285fee539SLionel Sambuc 	}
86385fee539SLionel Sambuc }
86485fee539SLionel Sambuc 
86585fee539SLionel Sambuc 
86685fee539SLionel Sambuc /*
86785fee539SLionel Sambuc  *	Rmtisatty.  Do the isatty function.
86885fee539SLionel Sambuc  */
86985fee539SLionel Sambuc int
rmtisatty(int fd)87085fee539SLionel Sambuc rmtisatty(int fd)
87185fee539SLionel Sambuc {
87285fee539SLionel Sambuc 
87385fee539SLionel Sambuc 	if (isrmt(fd))
87485fee539SLionel Sambuc 		return 0;
87585fee539SLionel Sambuc 	else
87685fee539SLionel Sambuc 		return isatty(fd);
87785fee539SLionel Sambuc }
87885fee539SLionel Sambuc 
87985fee539SLionel Sambuc 
88085fee539SLionel Sambuc /*
88185fee539SLionel Sambuc  *	Get file status, even if symlink.  Looks just like lstat(2) to caller.
88285fee539SLionel Sambuc  */
88385fee539SLionel Sambuc int
rmtlstat(const char * path,struct stat * buf)88485fee539SLionel Sambuc rmtlstat(const char *path, struct stat *buf)
88585fee539SLionel Sambuc {
88685fee539SLionel Sambuc 
88785fee539SLionel Sambuc 	_DIAGASSERT(path != NULL);
88885fee539SLionel Sambuc 	_DIAGASSERT(buf != NULL);
88985fee539SLionel Sambuc 
89085fee539SLionel Sambuc 	if (remdev(path)) {
89185fee539SLionel Sambuc 		errno = EOPNOTSUPP;
89285fee539SLionel Sambuc 		return -1;		/* For now (fnf) */
89385fee539SLionel Sambuc 	} else {
89485fee539SLionel Sambuc 		return lstat(path, buf);
89585fee539SLionel Sambuc 	}
89685fee539SLionel Sambuc }
897