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