1*4a3e2a82Sandvar /* $NetBSD: rmtlib.c,v 1.29 2024/03/22 19:36:56 andvar Exp $ */
267ead261Sjtc
367ead261Sjtc /*
467ead261Sjtc * rmt --- remote tape emulator subroutines
567ead261Sjtc *
667ead261Sjtc * Originally written by Jeff Lee, modified some by Arnold Robbins
767ead261Sjtc *
867ead261Sjtc * WARNING: The man page rmt(8) for /etc/rmt documents the remote mag
967ead261Sjtc * tape protocol which rdump and rrestore use. Unfortunately, the man
1067ead261Sjtc * page is *WRONG*. The author of the routines I'm including originally
1167ead261Sjtc * wrote his code just based on the man page, and it didn't work, so he
1267ead261Sjtc * went to the rdump source to figure out why. The only thing he had to
1367ead261Sjtc * change was to check for the 'F' return code in addition to the 'E',
1467ead261Sjtc * and to separate the various arguments with \n instead of a space. I
1567ead261Sjtc * personally don't think that this is much of a problem, but I wanted to
1667ead261Sjtc * point it out.
1767ead261Sjtc * -- Arnold Robbins
1867ead261Sjtc *
1967ead261Sjtc * Redone as a library that can replace open, read, write, etc, by
2067ead261Sjtc * Fred Fish, with some additional work by Arnold Robbins.
2167ead261Sjtc */
2267ead261Sjtc
2367ead261Sjtc /*
2467ead261Sjtc * MAXUNIT --- Maximum number of remote tape file units
2567ead261Sjtc *
2667ead261Sjtc * READ --- Return the number of the read side file descriptor
2767ead261Sjtc * WRITE --- Return the number of the write side file descriptor
2867ead261Sjtc */
2967ead261Sjtc
30e2d78706Slukem #include <sys/cdefs.h>
31*4a3e2a82Sandvar __RCSID("$NetBSD: rmtlib.c,v 1.29 2024/03/22 19:36:56 andvar Exp $");
32e2d78706Slukem
3367ead261Sjtc #define RMTIOCTL 1
34e6077a76Smikel /* #define USE_REXEC 1 */ /* rexec code courtesy of Dan Kegel, srs!dan */
3567ead261Sjtc
3667ead261Sjtc #include <sys/types.h>
37b48252f3Slukem #include <sys/stat.h>
3867ead261Sjtc
3967ead261Sjtc #ifdef RMTIOCTL
4067ead261Sjtc #include <sys/ioctl.h>
4167ead261Sjtc #include <sys/mtio.h>
4267ead261Sjtc #endif
4367ead261Sjtc
44b48252f3Slukem #include <assert.h>
45b48252f3Slukem #include <errno.h>
46b48252f3Slukem #include <fcntl.h>
47b48252f3Slukem #include <signal.h>
4832dd941fSlukem #include <stdarg.h>
49b48252f3Slukem #include <stdio.h>
50b48252f3Slukem #include <stdlib.h>
51b48252f3Slukem #include <string.h>
52b48252f3Slukem #include <unistd.h>
5388b197ecSchristos #include <err.h>
54b48252f3Slukem
5567ead261Sjtc #ifdef USE_REXEC
5667ead261Sjtc #include <netdb.h>
5767ead261Sjtc #endif
5867ead261Sjtc
596e190eedSthorpej #define __RMTLIB_PRIVATE
606e190eedSthorpej #include <rmt.h> /* get prototypes for remapped functions */
616e190eedSthorpej
625f2732abSmrg #include "pathnames.h"
635f2732abSmrg
6432dd941fSlukem static int _rmt_close(int);
6532dd941fSlukem static int _rmt_ioctl(int, unsigned long, void *);
6632dd941fSlukem static off_t _rmt_lseek(int, off_t, int);
6732dd941fSlukem static int _rmt_open(const char *, int, int);
6832dd941fSlukem static ssize_t _rmt_read(int, void *, size_t);
6932dd941fSlukem static ssize_t _rmt_write(int, const void *, size_t);
7088b197ecSchristos static int command(int, const char *);
7132dd941fSlukem static int remdev(const char *);
7232dd941fSlukem static void rmtabort(int);
7332dd941fSlukem static int status(int);
74ae6b9c67Slukem
75ae6b9c67Slukem
7667ead261Sjtc #define BUFMAGIC 64 /* a magic number for buffer sizes */
7767ead261Sjtc #define MAXUNIT 4
7867ead261Sjtc
7967ead261Sjtc #define READ(fd) (Ctp[fd][0])
8067ead261Sjtc #define WRITE(fd) (Ptc[fd][1])
8167ead261Sjtc
82e6077a76Smikel static int Ctp[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
83e6077a76Smikel static int Ptc[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
8467ead261Sjtc
8567ead261Sjtc
8667ead261Sjtc /*
878ee4077eSjtc * rmtabort --- close off a remote tape connection
8867ead261Sjtc */
89ae6b9c67Slukem static void
rmtabort(int fildes)9032dd941fSlukem rmtabort(int fildes)
9167ead261Sjtc {
9232dd941fSlukem
9367ead261Sjtc close(READ(fildes));
9467ead261Sjtc close(WRITE(fildes));
9567ead261Sjtc READ(fildes) = -1;
9667ead261Sjtc WRITE(fildes) = -1;
9767ead261Sjtc }
9867ead261Sjtc
9967ead261Sjtc
10067ead261Sjtc /*
10167ead261Sjtc * command --- attempt to perform a remote tape command
10267ead261Sjtc */
103ae6b9c67Slukem static int
command(int fildes,const char * buf)10488b197ecSchristos command(int fildes, const char *buf)
10567ead261Sjtc {
10632dd941fSlukem size_t blen;
10788b197ecSchristos sig_t pstat;
10867ead261Sjtc
109b48252f3Slukem _DIAGASSERT(buf != NULL);
110b48252f3Slukem
11167ead261Sjtc /*
11267ead261Sjtc * save current pipe status and try to make the request
11367ead261Sjtc */
11467ead261Sjtc
11567ead261Sjtc blen = strlen(buf);
11667ead261Sjtc pstat = signal(SIGPIPE, SIG_IGN);
117e1a2f47fSmatt if ((size_t)write(WRITE(fildes), buf, blen) == blen) {
11867ead261Sjtc signal(SIGPIPE, pstat);
11988b197ecSchristos return 0;
12067ead261Sjtc }
12167ead261Sjtc
12267ead261Sjtc /*
12367ead261Sjtc * something went wrong. close down and go home
12467ead261Sjtc */
12567ead261Sjtc
12667ead261Sjtc signal(SIGPIPE, pstat);
1278ee4077eSjtc rmtabort(fildes);
12867ead261Sjtc
12967ead261Sjtc errno = EIO;
13088b197ecSchristos return -1;
13167ead261Sjtc }
13267ead261Sjtc
13367ead261Sjtc
13467ead261Sjtc /*
13567ead261Sjtc * status --- retrieve the status from the pipe
13667ead261Sjtc */
137ae6b9c67Slukem static int
status(int fildes)13832dd941fSlukem status(int fildes)
13967ead261Sjtc {
14067ead261Sjtc int i;
14167ead261Sjtc char c, *cp;
14267ead261Sjtc char buffer[BUFMAGIC];
14367ead261Sjtc
14467ead261Sjtc /*
14567ead261Sjtc * read the reply command line
14667ead261Sjtc */
14767ead261Sjtc
14832dd941fSlukem for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++) {
14932dd941fSlukem if (read(READ(fildes), cp, 1) != 1) {
1508ee4077eSjtc rmtabort(fildes);
15167ead261Sjtc errno = EIO;
15288b197ecSchristos return -1;
15367ead261Sjtc }
15432dd941fSlukem if (*cp == '\n') {
15567ead261Sjtc *cp = 0;
15667ead261Sjtc break;
15767ead261Sjtc }
15867ead261Sjtc }
15967ead261Sjtc
16032dd941fSlukem if (i == BUFMAGIC) {
1618ee4077eSjtc rmtabort(fildes);
16267ead261Sjtc errno = EIO;
16388b197ecSchristos return -1;
16467ead261Sjtc }
16567ead261Sjtc
16667ead261Sjtc /*
16767ead261Sjtc * check the return status
16867ead261Sjtc */
16967ead261Sjtc
17067ead261Sjtc for (cp = buffer; *cp; cp++)
17167ead261Sjtc if (*cp != ' ')
17267ead261Sjtc break;
17367ead261Sjtc
17432dd941fSlukem if (*cp == 'E' || *cp == 'F') {
17567ead261Sjtc errno = atoi(cp + 1);
17667ead261Sjtc while (read(READ(fildes), &c, 1) == 1)
17767ead261Sjtc if (c == '\n')
17867ead261Sjtc break;
17967ead261Sjtc
18067ead261Sjtc if (*cp == 'F')
1818ee4077eSjtc rmtabort(fildes);
18267ead261Sjtc
18388b197ecSchristos return -1;
18467ead261Sjtc }
18567ead261Sjtc
18667ead261Sjtc /*
18767ead261Sjtc * check for mis-synced pipes
18867ead261Sjtc */
18967ead261Sjtc
19032dd941fSlukem if (*cp != 'A') {
1918ee4077eSjtc rmtabort(fildes);
19267ead261Sjtc errno = EIO;
19388b197ecSchristos return -1;
19467ead261Sjtc }
19567ead261Sjtc
19688b197ecSchristos return atoi(cp + 1);
19767ead261Sjtc }
19867ead261Sjtc
19967ead261Sjtc
20032dd941fSlukem #ifdef USE_REXEC
20167ead261Sjtc /*
20267ead261Sjtc * _rmt_rexec
20367ead261Sjtc *
20467ead261Sjtc * execute /etc/rmt on a remote system using rexec().
20567ead261Sjtc * Return file descriptor of bidirectional socket for stdin and stdout
20667ead261Sjtc * If username is NULL, or an empty string, uses current username.
20767ead261Sjtc *
20867ead261Sjtc * ADR: By default, this code is not used, since it requires that
20967ead261Sjtc * the user have a .netrc file in his/her home directory, or that the
21067ead261Sjtc * application designer be willing to have rexec prompt for login and
21167ead261Sjtc * password info. This may be unacceptable, and .rhosts files for use
21267ead261Sjtc * with rsh are much more common on BSD systems.
21367ead261Sjtc */
21467ead261Sjtc
21532dd941fSlukem static int _rmt_rexec(const char *, const char *);
216ae6b9c67Slukem
21767ead261Sjtc static int
_rmt_rexec(const char * host,const char * user)21832dd941fSlukem _rmt_rexec(const char *host, const char *user)
21967ead261Sjtc {
22067ead261Sjtc struct servent *rexecserv;
22167ead261Sjtc
222b48252f3Slukem _DIAGASSERT(host != NULL);
223b48252f3Slukem /* user may be NULL */
224b48252f3Slukem
22567ead261Sjtc rexecserv = getservbyname("exec", "tcp");
22688b197ecSchristos if (rexecserv == NULL)
22777c15e81Smrg errx(1, "exec/tcp: service not available.");
22867ead261Sjtc if ((user != NULL) && *user == '\0')
22943ca618dSenami user = NULL;
23088b197ecSchristos return rexec(&host, rexecserv->s_port, user, NULL,
23188b197ecSchristos "/etc/rmt", NULL);
23267ead261Sjtc }
23367ead261Sjtc #endif /* USE_REXEC */
23467ead261Sjtc
23532dd941fSlukem
23667ead261Sjtc /*
23767ead261Sjtc * _rmt_open --- open a magtape device on system specified, as given user
23867ead261Sjtc *
23967ead261Sjtc * file name has the form [user@]system:/dev/????
24067ead261Sjtc #ifdef COMPAT
24167ead261Sjtc * file name has the form system[.user]:/dev/????
24267ead261Sjtc #endif
24367ead261Sjtc */
24467ead261Sjtc
24567ead261Sjtc #define MAXHOSTLEN 257 /* BSD allows very long host names... */
24667ead261Sjtc
247ae6b9c67Slukem static int
24844fad74bSchristos /*ARGSUSED*/
_rmt_open(const char * path,int oflag,int mode)24932dd941fSlukem _rmt_open(const char *path, int oflag, int mode)
25067ead261Sjtc {
25188b197ecSchristos int i;
252d3574aa7Schristos char buffer[2 * BUFMAGIC];
2536a973ed8Slukem char host[MAXHOSTLEN];
25467ead261Sjtc char device[BUFMAGIC];
25567ead261Sjtc char login[BUFMAGIC];
25667ead261Sjtc char *sys, *dev, *user;
257e1a2f47fSmatt const char *rshpath, *rsh;
25867ead261Sjtc
259b48252f3Slukem _DIAGASSERT(path != NULL);
260b48252f3Slukem
2616a973ed8Slukem sys = host;
26267ead261Sjtc dev = device;
26367ead261Sjtc user = login;
26467ead261Sjtc
26567ead261Sjtc /*
26667ead261Sjtc * first, find an open pair of file descriptors
26767ead261Sjtc */
26867ead261Sjtc
26967ead261Sjtc for (i = 0; i < MAXUNIT; i++)
27067ead261Sjtc if (READ(i) == -1 && WRITE(i) == -1)
27167ead261Sjtc break;
27267ead261Sjtc
27332dd941fSlukem if (i == MAXUNIT) {
27467ead261Sjtc errno = EMFILE;
27588b197ecSchristos return -1;
27667ead261Sjtc }
27767ead261Sjtc
27867ead261Sjtc /*
27967ead261Sjtc * pull apart system and device, and optional user
28067ead261Sjtc * don't munge original string
28167ead261Sjtc * if COMPAT is defined, also handle old (4.2) style person.site notation.
28267ead261Sjtc */
28367ead261Sjtc
28467ead261Sjtc while (*path != '@'
28567ead261Sjtc #ifdef COMPAT
28667ead261Sjtc && *path != '.'
28767ead261Sjtc #endif
28867ead261Sjtc && *path != ':') {
28967ead261Sjtc *sys++ = *path++;
29067ead261Sjtc }
29167ead261Sjtc *sys = '\0';
29267ead261Sjtc path++;
29367ead261Sjtc
29432dd941fSlukem if (*(path - 1) == '@') {
295d3574aa7Schristos (void)strlcpy(user, host, sizeof(login));
2969cd5492cSmrg /* saw user part of user@host */
2976a973ed8Slukem sys = host; /* start over */
29867ead261Sjtc while (*path != ':') {
29967ead261Sjtc *sys++ = *path++;
30067ead261Sjtc }
30167ead261Sjtc *sys = '\0';
30267ead261Sjtc path++;
30367ead261Sjtc }
30467ead261Sjtc #ifdef COMPAT
30532dd941fSlukem else if (*(path - 1) == '.') {
30667ead261Sjtc while (*path != ':') {
30767ead261Sjtc *user++ = *path++;
30867ead261Sjtc }
30967ead261Sjtc *user = '\0';
31067ead261Sjtc path++;
31167ead261Sjtc }
31267ead261Sjtc #endif
31367ead261Sjtc else
31467ead261Sjtc *user = '\0';
31567ead261Sjtc
31667ead261Sjtc while (*path) {
31767ead261Sjtc *dev++ = *path++;
31867ead261Sjtc }
31967ead261Sjtc *dev = '\0';
32067ead261Sjtc
32167ead261Sjtc #ifdef USE_REXEC
32267ead261Sjtc /*
32367ead261Sjtc * Execute the remote command using rexec
32467ead261Sjtc */
3256a973ed8Slukem READ(i) = WRITE(i) = _rmt_rexec(host, login);
32667ead261Sjtc if (READ(i) < 0)
32788b197ecSchristos return -1;
32867ead261Sjtc #else
32967ead261Sjtc /*
33067ead261Sjtc * setup the pipes for the 'rsh' command and fork
33167ead261Sjtc */
33267ead261Sjtc
33367ead261Sjtc if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
33488b197ecSchristos return -1;
33567ead261Sjtc
33688b197ecSchristos switch (fork()) {
33788b197ecSchristos case -1:
33888b197ecSchristos return -1;
33967ead261Sjtc
34088b197ecSchristos case 0:
34167ead261Sjtc close(0);
34267ead261Sjtc dup(Ptc[i][0]);
34367ead261Sjtc close(Ptc[i][0]); close(Ptc[i][1]);
34467ead261Sjtc close(1);
34567ead261Sjtc dup(Ctp[i][1]);
34667ead261Sjtc close(Ctp[i][0]); close(Ctp[i][1]);
34767ead261Sjtc (void) setuid(getuid());
34867ead261Sjtc (void) setgid(getgid());
3495f2732abSmrg
3505f2732abSmrg if ((rshpath = getenv("RCMD_CMD")) == NULL)
3515f2732abSmrg rshpath = _PATH_RSH;
3525f2732abSmrg if ((rsh = strrchr(rshpath, '/')) == NULL)
3535f2732abSmrg rsh = rshpath;
3545f2732abSmrg else
3555f2732abSmrg rsh++;
3565f2732abSmrg
35732dd941fSlukem if (*login) {
35888b197ecSchristos execl(rshpath, rsh, host, "-l", login, _PATH_RMT, NULL);
35932dd941fSlukem } else {
36088b197ecSchristos execl(rshpath, rsh, host, _PATH_RMT, NULL);
36167ead261Sjtc }
36267ead261Sjtc
36367ead261Sjtc /*
36467ead261Sjtc * bad problems if we get here
36567ead261Sjtc */
36667ead261Sjtc
367*4a3e2a82Sandvar err(1, "Cannot exec %s", rshpath);
36888b197ecSchristos /*FALLTHROUGH*/
36988b197ecSchristos default:
37088b197ecSchristos break;
37167ead261Sjtc }
37267ead261Sjtc
37367ead261Sjtc close(Ptc[i][0]); close(Ctp[i][1]);
37467ead261Sjtc #endif
37567ead261Sjtc
37667ead261Sjtc /*
37767ead261Sjtc * now attempt to open the tape device
37867ead261Sjtc */
37967ead261Sjtc
3809cd5492cSmrg (void)snprintf(buffer, sizeof(buffer), "O%s\n%d\n", device, oflag);
38167ead261Sjtc if (command(i, buffer) == -1 || status(i) == -1)
38288b197ecSchristos return -1;
38367ead261Sjtc
38488b197ecSchristos return i;
38567ead261Sjtc }
38667ead261Sjtc
38767ead261Sjtc
38867ead261Sjtc /*
38967ead261Sjtc * _rmt_close --- close a remote magtape unit and shut down
39067ead261Sjtc */
391ae6b9c67Slukem static int
_rmt_close(int fildes)39232dd941fSlukem _rmt_close(int fildes)
39367ead261Sjtc {
39467ead261Sjtc int rc;
39567ead261Sjtc
39632dd941fSlukem if (command(fildes, "C\n") != -1) {
39767ead261Sjtc rc = status(fildes);
39867ead261Sjtc
3998ee4077eSjtc rmtabort(fildes);
40088b197ecSchristos return rc;
40167ead261Sjtc }
40267ead261Sjtc
40388b197ecSchristos return -1;
40467ead261Sjtc }
40567ead261Sjtc
40667ead261Sjtc
40767ead261Sjtc /*
40867ead261Sjtc * _rmt_read --- read a buffer from a remote tape
40967ead261Sjtc */
41032dd941fSlukem static ssize_t
_rmt_read(int fildes,void * buf,size_t nbyte)41132dd941fSlukem _rmt_read(int fildes, void *buf, size_t nbyte)
41267ead261Sjtc {
41344fad74bSchristos size_t rc;
41444fad74bSchristos int rv;
41544fad74bSchristos ssize_t nread;
41632dd941fSlukem char *p;
41767ead261Sjtc char buffer[BUFMAGIC];
41867ead261Sjtc
419b48252f3Slukem _DIAGASSERT(buf != NULL);
420b48252f3Slukem
42188b197ecSchristos (void)snprintf(buffer, sizeof buffer, "R%zu\n", nbyte);
42244fad74bSchristos if (command(fildes, buffer) == -1 || (rv = status(fildes)) == -1)
42388b197ecSchristos return -1;
42467ead261Sjtc
425e1a2f47fSmatt if (rv > (int)nbyte)
42688b197ecSchristos rv = (int)nbyte;
42744fad74bSchristos
42844fad74bSchristos for (rc = rv, p = buf; rc > 0; rc -= nread, p += nread) {
42944fad74bSchristos if ((nread = read(READ(fildes), p, rc)) <= 0) {
4308ee4077eSjtc rmtabort(fildes);
43167ead261Sjtc errno = EIO;
43288b197ecSchristos return -1;
43367ead261Sjtc }
43467ead261Sjtc }
43567ead261Sjtc
43644fad74bSchristos return rv;
43767ead261Sjtc }
43867ead261Sjtc
43967ead261Sjtc
44067ead261Sjtc /*
44167ead261Sjtc * _rmt_write --- write a buffer to the remote tape
44267ead261Sjtc */
44332dd941fSlukem static ssize_t
_rmt_write(int fildes,const void * buf,size_t nbyte)44432dd941fSlukem _rmt_write(int fildes, const void *buf, size_t nbyte)
44567ead261Sjtc {
44667ead261Sjtc char buffer[BUFMAGIC];
44788b197ecSchristos sig_t pstat;
44867ead261Sjtc
449b48252f3Slukem _DIAGASSERT(buf != NULL);
450b48252f3Slukem
45188b197ecSchristos (void)snprintf(buffer, sizeof buffer, "W%zu\n", nbyte);
45267ead261Sjtc if (command(fildes, buffer) == -1)
45388b197ecSchristos return -1;
45467ead261Sjtc
45567ead261Sjtc pstat = signal(SIGPIPE, SIG_IGN);
456e1a2f47fSmatt if ((size_t)write(WRITE(fildes), buf, nbyte) == nbyte) {
45767ead261Sjtc signal(SIGPIPE, pstat);
45888b197ecSchristos return status(fildes);
45967ead261Sjtc }
46067ead261Sjtc
46167ead261Sjtc signal(SIGPIPE, pstat);
4628ee4077eSjtc rmtabort(fildes);
46367ead261Sjtc errno = EIO;
46488b197ecSchristos return -1;
46567ead261Sjtc }
46667ead261Sjtc
46767ead261Sjtc
46867ead261Sjtc /*
46967ead261Sjtc * _rmt_lseek --- perform an imitation lseek operation remotely
47067ead261Sjtc */
471ae6b9c67Slukem static off_t
_rmt_lseek(int fildes,off_t offset,int whence)47232dd941fSlukem _rmt_lseek(int fildes, off_t offset, int whence)
47367ead261Sjtc {
47467ead261Sjtc char buffer[BUFMAGIC];
47567ead261Sjtc
47644fad74bSchristos /*LONGLONG*/
47732dd941fSlukem (void)snprintf(buffer, sizeof buffer, "L%lld\n%d\n", (long long)offset,
478395c20eaSmrg whence);
47967ead261Sjtc if (command(fildes, buffer) == -1)
48088b197ecSchristos return -1;
48167ead261Sjtc
48288b197ecSchristos return status(fildes);
48367ead261Sjtc }
48467ead261Sjtc
48567ead261Sjtc
48667ead261Sjtc /*
48767ead261Sjtc * _rmt_ioctl --- perform raw tape operations remotely
48867ead261Sjtc */
48967ead261Sjtc #ifdef RMTIOCTL
490ae6b9c67Slukem static int
_rmt_ioctl(int fildes,unsigned long op,void * arg)49132dd941fSlukem _rmt_ioctl(int fildes, unsigned long op, void *arg)
49267ead261Sjtc {
49367ead261Sjtc char c;
49444fad74bSchristos int rv;
49544fad74bSchristos size_t rc;
49644fad74bSchristos ssize_t cnt;
49732dd941fSlukem char buffer[BUFMAGIC], *p;
49888b197ecSchristos struct mtop *mtop = arg;
49967ead261Sjtc
500b48252f3Slukem _DIAGASSERT(arg != NULL);
501b48252f3Slukem
50267ead261Sjtc /*
503a0403cdeSmsaitoh * MTIOCOP is the easy one. nothing is transferred in binary
50467ead261Sjtc */
50567ead261Sjtc
50632dd941fSlukem if (op == MTIOCTOP) {
5079cd5492cSmrg (void)snprintf(buffer, sizeof buffer, "I%d\n%d\n",
50888b197ecSchristos mtop->mt_op, mtop->mt_count);
50967ead261Sjtc if (command(fildes, buffer) == -1)
51088b197ecSchristos return -1;
51188b197ecSchristos return status(fildes);
51267ead261Sjtc }
51367ead261Sjtc
51467ead261Sjtc /*
51567ead261Sjtc * we can only handle 2 ops, if not the other one, punt
51667ead261Sjtc */
51767ead261Sjtc
51832dd941fSlukem if (op != MTIOCGET) {
51967ead261Sjtc errno = EINVAL;
52088b197ecSchristos return -1;
52167ead261Sjtc }
52267ead261Sjtc
52367ead261Sjtc /*
52467ead261Sjtc * grab the status and read it directly into the structure
52567ead261Sjtc * this assumes that the status buffer is (hopefully) not
52667ead261Sjtc * padded and that 2 shorts fit in a long without any word
52767ead261Sjtc * alignment problems, ie - the whole struct is contiguous
52867ead261Sjtc * NOTE - this is probably NOT a good assumption.
52967ead261Sjtc */
53067ead261Sjtc
53144fad74bSchristos if (command(fildes, "S") == -1 || (rv = status(fildes)) == -1)
53288b197ecSchristos return -1;
53367ead261Sjtc
53488b197ecSchristos memset(arg, 0, sizeof(struct mtget));
53544fad74bSchristos for (rc = rv, p = arg; rc > 0; rc -= cnt, p += cnt) {
53644fad74bSchristos if ((cnt = read(READ(fildes), p, rc)) <= 0) {
5378ee4077eSjtc rmtabort(fildes);
53867ead261Sjtc errno = EIO;
53988b197ecSchristos return -1;
54067ead261Sjtc }
54167ead261Sjtc }
54267ead261Sjtc
54367ead261Sjtc /*
54467ead261Sjtc * now we check for byte position. mt_type is a small integer field
54567ead261Sjtc * (normally) so we will check its magnitude. if it is larger than
54667ead261Sjtc * 256, we will assume that the bytes are swapped and go through
54767ead261Sjtc * and reverse all the bytes
54867ead261Sjtc */
54967ead261Sjtc
55044fad74bSchristos if (((struct mtget *)(void *)p)->mt_type < 256)
55188b197ecSchristos return 0;
55267ead261Sjtc
5531acc9100Schristos for (cnt = 0; cnt < rv; cnt += 2) {
55432dd941fSlukem c = p[cnt];
55532dd941fSlukem p[cnt] = p[cnt + 1];
55632dd941fSlukem p[cnt + 1] = c;
55767ead261Sjtc }
55867ead261Sjtc
55988b197ecSchristos return 0;
56067ead261Sjtc }
56167ead261Sjtc #endif /* RMTIOCTL */
56267ead261Sjtc
56332dd941fSlukem
56467ead261Sjtc /*
56567ead261Sjtc * Added routines to replace open(), close(), lseek(), ioctl(), etc.
56667ead261Sjtc * The preprocessor can be used to remap these the rmtopen(), etc
56767ead261Sjtc * thus minimizing source changes:
56867ead261Sjtc *
56967ead261Sjtc * #ifdef <something>
57067ead261Sjtc * # define access rmtaccess
57167ead261Sjtc * # define close rmtclose
57267ead261Sjtc * # define creat rmtcreat
57367ead261Sjtc * # define dup rmtdup
57467ead261Sjtc * # define fcntl rmtfcntl
57567ead261Sjtc * # define fstat rmtfstat
57667ead261Sjtc * # define ioctl rmtioctl
57767ead261Sjtc * # define isatty rmtisatty
57867ead261Sjtc * # define lseek rmtlseek
57967ead261Sjtc * # define lstat rmtlstat
58067ead261Sjtc * # define open rmtopen
58167ead261Sjtc * # define read rmtread
58267ead261Sjtc * # define stat rmtstat
58367ead261Sjtc * # define write rmtwrite
58467ead261Sjtc * #endif
58567ead261Sjtc *
58667ead261Sjtc * -- Fred Fish
58767ead261Sjtc *
58867ead261Sjtc * ADR --- I set up a <rmt.h> include file for this
58967ead261Sjtc *
59067ead261Sjtc */
59167ead261Sjtc
59267ead261Sjtc /*
59367ead261Sjtc * Note that local vs remote file descriptors are distinquished
59467ead261Sjtc * by adding a bias to the remote descriptors. This is a quick
59567ead261Sjtc * and dirty trick that may not be portable to some systems.
59667ead261Sjtc */
59767ead261Sjtc
59867ead261Sjtc #define REM_BIAS 128
59967ead261Sjtc
60067ead261Sjtc
60167ead261Sjtc /*
60267ead261Sjtc * Test pathname to see if it is local or remote. A remote device
60367ead261Sjtc * is any string that contains ":/dev/". Returns 1 if remote,
60467ead261Sjtc * 0 otherwise.
60567ead261Sjtc */
60667ead261Sjtc
607ae6b9c67Slukem static int
remdev(const char * path)60832dd941fSlukem remdev(const char *path)
60967ead261Sjtc {
610b48252f3Slukem
611b48252f3Slukem _DIAGASSERT(path != NULL);
612b48252f3Slukem
61332dd941fSlukem if ((path = strchr(path, ':')) != NULL) {
61432dd941fSlukem if (strncmp(path + 1, "/dev/", 5) == 0) {
61588b197ecSchristos return 1;
61667ead261Sjtc }
61767ead261Sjtc }
61888b197ecSchristos return 0;
61967ead261Sjtc }
62067ead261Sjtc
62167ead261Sjtc
62267ead261Sjtc /*
62367ead261Sjtc * Open a local or remote file. Looks just like open(2) to
62467ead261Sjtc * caller.
62567ead261Sjtc */
626ae6b9c67Slukem int
rmtopen(const char * path,int oflag,...)6276e190eedSthorpej rmtopen(const char *path, int oflag, ...)
6286e190eedSthorpej {
6296e190eedSthorpej mode_t mode;
6306e190eedSthorpej int fd;
6316e190eedSthorpej va_list ap;
6326e190eedSthorpej va_start(ap, oflag);
6336e190eedSthorpej
6346e190eedSthorpej mode = va_arg(ap, mode_t);
6356e190eedSthorpej va_end(ap);
63667ead261Sjtc
637b48252f3Slukem _DIAGASSERT(path != NULL);
638b48252f3Slukem
63932dd941fSlukem if (remdev(path)) {
64044fad74bSchristos fd = _rmt_open(path, oflag, (int)mode);
64167ead261Sjtc
64288b197ecSchristos return (fd == -1) ? -1 : (fd + REM_BIAS);
64332dd941fSlukem } else {
64488b197ecSchristos return open(path, oflag, mode);
64567ead261Sjtc }
64667ead261Sjtc }
64767ead261Sjtc
64867ead261Sjtc /*
64967ead261Sjtc * Test pathname for specified access. Looks just like access(2)
65067ead261Sjtc * to caller.
65167ead261Sjtc */
65267ead261Sjtc
653ae6b9c67Slukem int
rmtaccess(const char * path,int amode)65432dd941fSlukem rmtaccess(const char *path, int amode)
65567ead261Sjtc {
656b48252f3Slukem
657b48252f3Slukem _DIAGASSERT(path != NULL);
658b48252f3Slukem
65932dd941fSlukem if (remdev(path)) {
66088b197ecSchristos return 0; /* Let /etc/rmt find out */
66132dd941fSlukem } else {
66288b197ecSchristos return access(path, amode);
66367ead261Sjtc }
66467ead261Sjtc }
66567ead261Sjtc
66667ead261Sjtc
66767ead261Sjtc /*
668e6077a76Smikel * Isrmt. Let a programmer know he has a remote device.
669e6077a76Smikel */
670ae6b9c67Slukem int
isrmt(int fd)67132dd941fSlukem isrmt(int fd)
672e6077a76Smikel {
673f836d171Spooka int unbias = fd - REM_BIAS;
67432dd941fSlukem
675f836d171Spooka return (fd >= REM_BIAS) && unbias < MAXUNIT &&
676f836d171Spooka (WRITE(unbias) != -1 || READ(unbias) != -1);
677e6077a76Smikel }
678e6077a76Smikel
679e6077a76Smikel
680e6077a76Smikel /*
68167ead261Sjtc * Read from stream. Looks just like read(2) to caller.
68267ead261Sjtc */
683ae6b9c67Slukem ssize_t
rmtread(int fildes,void * buf,size_t nbyte)68432dd941fSlukem rmtread(int fildes, void *buf, size_t nbyte)
68567ead261Sjtc {
686b48252f3Slukem
687b48252f3Slukem _DIAGASSERT(buf != NULL);
688b48252f3Slukem
68932dd941fSlukem if (isrmt(fildes)) {
69088b197ecSchristos return _rmt_read(fildes - REM_BIAS, buf, nbyte);
69132dd941fSlukem } else {
69288b197ecSchristos return read(fildes, buf, nbyte);
69367ead261Sjtc }
69467ead261Sjtc }
69567ead261Sjtc
69667ead261Sjtc
69767ead261Sjtc /*
69867ead261Sjtc * Write to stream. Looks just like write(2) to caller.
69967ead261Sjtc */
700ae6b9c67Slukem ssize_t
rmtwrite(int fildes,const void * buf,size_t nbyte)70132dd941fSlukem rmtwrite(int fildes, const void *buf, size_t nbyte)
70267ead261Sjtc {
703b48252f3Slukem
704b48252f3Slukem _DIAGASSERT(buf != NULL);
705b48252f3Slukem
70632dd941fSlukem if (isrmt(fildes)) {
70788b197ecSchristos return _rmt_write(fildes - REM_BIAS, buf, nbyte);
70832dd941fSlukem } else {
70988b197ecSchristos return write(fildes, buf, nbyte);
71067ead261Sjtc }
71167ead261Sjtc }
71267ead261Sjtc
71367ead261Sjtc /*
71467ead261Sjtc * Perform lseek on file. Looks just like lseek(2) to caller.
71567ead261Sjtc */
716ae6b9c67Slukem off_t
rmtlseek(int fildes,off_t offset,int whence)71732dd941fSlukem rmtlseek(int fildes, off_t offset, int whence)
71867ead261Sjtc {
71943ca618dSenami
72032dd941fSlukem if (isrmt(fildes)) {
72188b197ecSchristos return _rmt_lseek(fildes - REM_BIAS, offset, whence);
72232dd941fSlukem } else {
72388b197ecSchristos return lseek(fildes, offset, whence);
72467ead261Sjtc }
72567ead261Sjtc }
72667ead261Sjtc
72767ead261Sjtc
72867ead261Sjtc /*
72967ead261Sjtc * Close a file. Looks just like close(2) to caller.
73067ead261Sjtc */
731ae6b9c67Slukem int
rmtclose(int fildes)73232dd941fSlukem rmtclose(int fildes)
73367ead261Sjtc {
73443ca618dSenami
73532dd941fSlukem if (isrmt(fildes)) {
73688b197ecSchristos return _rmt_close(fildes - REM_BIAS);
73732dd941fSlukem } else {
73888b197ecSchristos return close(fildes);
73967ead261Sjtc }
74067ead261Sjtc }
74167ead261Sjtc
74232dd941fSlukem
74367ead261Sjtc /*
74467ead261Sjtc * Do ioctl on file. Looks just like ioctl(2) to caller.
74567ead261Sjtc */
746ae6b9c67Slukem int
rmtioctl(int fildes,unsigned long request,...)7476e190eedSthorpej rmtioctl(int fildes, unsigned long request, ...)
7486e190eedSthorpej {
74988b197ecSchristos void *arg;
7506e190eedSthorpej va_list ap;
7516e190eedSthorpej va_start(ap, request);
7526e190eedSthorpej
75388b197ecSchristos arg = va_arg(ap, void *);
7546e190eedSthorpej va_end(ap);
7556e190eedSthorpej
756b48252f3Slukem /* XXX: arg may be NULL ? */
757b48252f3Slukem
75832dd941fSlukem if (isrmt(fildes)) {
75967ead261Sjtc #ifdef RMTIOCTL
76088b197ecSchristos return _rmt_ioctl(fildes - REM_BIAS, request, arg);
76167ead261Sjtc #else
76267ead261Sjtc errno = EOPNOTSUPP;
76388b197ecSchristos return -1; /* For now (fnf) */
76467ead261Sjtc #endif
76532dd941fSlukem } else {
76688b197ecSchristos return ioctl(fildes, request, arg);
76767ead261Sjtc }
76867ead261Sjtc }
76967ead261Sjtc
77067ead261Sjtc
77167ead261Sjtc /*
77267ead261Sjtc * Duplicate an open file descriptor. Looks just like dup(2)
77367ead261Sjtc * to caller.
77467ead261Sjtc */
775ae6b9c67Slukem int
rmtdup(int fildes)77632dd941fSlukem rmtdup(int fildes)
77767ead261Sjtc {
77843ca618dSenami
77932dd941fSlukem if (isrmt(fildes)) {
78067ead261Sjtc errno = EOPNOTSUPP;
78188b197ecSchristos return -1; /* For now (fnf) */
78232dd941fSlukem } else {
78388b197ecSchristos return dup(fildes);
78467ead261Sjtc }
78567ead261Sjtc }
78667ead261Sjtc
78732dd941fSlukem
78867ead261Sjtc /*
78967ead261Sjtc * Get file status. Looks just like fstat(2) to caller.
79067ead261Sjtc */
791ae6b9c67Slukem int
rmtfstat(int fildes,struct stat * buf)79232dd941fSlukem rmtfstat(int fildes, struct stat *buf)
79367ead261Sjtc {
794b48252f3Slukem
795b48252f3Slukem _DIAGASSERT(buf != NULL);
796b48252f3Slukem
79732dd941fSlukem if (isrmt(fildes)) {
79867ead261Sjtc errno = EOPNOTSUPP;
79988b197ecSchristos return -1; /* For now (fnf) */
80032dd941fSlukem } else {
80188b197ecSchristos return fstat(fildes, buf);
80267ead261Sjtc }
80367ead261Sjtc }
80467ead261Sjtc
80567ead261Sjtc
80667ead261Sjtc /*
80767ead261Sjtc * Get file status. Looks just like stat(2) to caller.
80867ead261Sjtc */
809ae6b9c67Slukem int
rmtstat(const char * path,struct stat * buf)81032dd941fSlukem rmtstat(const char *path, struct stat *buf)
81167ead261Sjtc {
812b48252f3Slukem
813b48252f3Slukem _DIAGASSERT(path != NULL);
814b48252f3Slukem _DIAGASSERT(buf != NULL);
815b48252f3Slukem
81632dd941fSlukem if (remdev(path)) {
81767ead261Sjtc errno = EOPNOTSUPP;
81888b197ecSchristos return -1; /* For now (fnf) */
81932dd941fSlukem } else {
82088b197ecSchristos return stat(path, buf);
82167ead261Sjtc }
82267ead261Sjtc }
82367ead261Sjtc
82467ead261Sjtc
82567ead261Sjtc /*
82667ead261Sjtc * Create a file from scratch. Looks just like creat(2) to the caller.
82767ead261Sjtc */
828ae6b9c67Slukem int
rmtcreat(const char * path,mode_t mode)82932dd941fSlukem rmtcreat(const char *path, mode_t mode)
83067ead261Sjtc {
831b48252f3Slukem
832b48252f3Slukem _DIAGASSERT(path != NULL);
833b48252f3Slukem
83432dd941fSlukem if (remdev(path)) {
83588b197ecSchristos return rmtopen(path, O_WRONLY | O_CREAT, mode);
83632dd941fSlukem } else {
83788b197ecSchristos return open(path, O_CREAT | O_TRUNC | O_WRONLY, mode);
83867ead261Sjtc }
83967ead261Sjtc }
84067ead261Sjtc
84132dd941fSlukem
84267ead261Sjtc /*
84367ead261Sjtc * Rmtfcntl. Do a remote fcntl operation.
84467ead261Sjtc */
845ae6b9c67Slukem int
rmtfcntl(int fd,int cmd,...)8466e190eedSthorpej rmtfcntl(int fd, int cmd, ...)
84767ead261Sjtc {
8486e190eedSthorpej void *arg;
8496e190eedSthorpej va_list ap;
8506e190eedSthorpej va_start(ap, cmd);
8516e190eedSthorpej
8526e190eedSthorpej arg = va_arg(ap, void *);
8536e190eedSthorpej va_end(ap);
8546e190eedSthorpej
855b48252f3Slukem /* XXX: arg may be NULL ? */
856b48252f3Slukem
85732dd941fSlukem if (isrmt(fd)) {
85867ead261Sjtc errno = EOPNOTSUPP;
85988b197ecSchristos return -1;
86032dd941fSlukem } else {
86188b197ecSchristos return fcntl(fd, cmd, arg);
86267ead261Sjtc }
86367ead261Sjtc }
86467ead261Sjtc
86532dd941fSlukem
86667ead261Sjtc /*
86767ead261Sjtc * Rmtisatty. Do the isatty function.
86867ead261Sjtc */
869ae6b9c67Slukem int
rmtisatty(int fd)87032dd941fSlukem rmtisatty(int fd)
87167ead261Sjtc {
87232dd941fSlukem
87367ead261Sjtc if (isrmt(fd))
87488b197ecSchristos return 0;
87567ead261Sjtc else
87688b197ecSchristos return isatty(fd);
87767ead261Sjtc }
87867ead261Sjtc
87967ead261Sjtc
88067ead261Sjtc /*
88167ead261Sjtc * Get file status, even if symlink. Looks just like lstat(2) to caller.
88267ead261Sjtc */
883ae6b9c67Slukem int
rmtlstat(const char * path,struct stat * buf)88432dd941fSlukem rmtlstat(const char *path, struct stat *buf)
88567ead261Sjtc {
886b48252f3Slukem
887b48252f3Slukem _DIAGASSERT(path != NULL);
888b48252f3Slukem _DIAGASSERT(buf != NULL);
889b48252f3Slukem
89032dd941fSlukem if (remdev(path)) {
89167ead261Sjtc errno = EOPNOTSUPP;
89288b197ecSchristos return -1; /* For now (fnf) */
89332dd941fSlukem } else {
89488b197ecSchristos return lstat(path, buf);
89567ead261Sjtc }
89667ead261Sjtc }
897