1 /* Remote tape emulator subroutines.
2 Copyright (C) 1988 Free Software Foundation
4 This file is part of GNU Tar.
6 GNU Tar is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
11 GNU Tar is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Tar; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* JF: modified to make all rmtXXX calls into macros for speed */
23 static char *RCSid
= "$Header: /pub/NetBSD/misc/repositories/cvsroot/src/gnu/usr.bin/tar/Attic/rtape_lib.c,v 1.1 1993/03/21 09:58:31 cgd Exp $";
28 * Revision 1.7 89/03/23 14:09:51 root
29 * Fix from haynes@ucscc.ucsc.edu for use w/compat. ADR.
31 * Revision 1.6 88/10/25 17:04:29 root
32 * rexec code and a bug fix from srs!dan, miscellanious cleanup. ADR.
34 * Revision 1.5 88/10/25 16:30:17 root
35 * Fix from jeff@gatech.edu for getting user@host:dev right. ADR.
37 * Revision 1.4 87/10/30 10:36:12 root
38 * Made 4.2 syntax a compile time option. ADR.
40 * Revision 1.3 87/04/22 11:16:48 root
41 * Two fixes from parmelee@wayback.cs.cornell.edu to correctly
42 * do fd biasing and rmt protocol on 'S' command. ADR.
44 * Revision 1.2 86/10/09 16:38:53 root
45 * Changed to reflect 4.3BSD rcp syntax. ADR.
47 * Revision 1.1 86/10/09 16:17:35 root
53 * rmt --- remote tape emulator subroutines
55 * Originally written by Jeff Lee, modified some by Arnold Robbins
57 * WARNING: The man page rmt(8) for /etc/rmt documents the remote mag
58 * tape protocol which rdump and rrestore use. Unfortunately, the man
59 * page is *WRONG*. The author of the routines I'm including originally
60 * wrote his code just based on the man page, and it didn't work, so he
61 * went to the rdump source to figure out why. The only thing he had to
62 * change was to check for the 'F' return code in addition to the 'E',
63 * and to separate the various arguments with \n instead of a space. I
64 * personally don't think that this is much of a problem, but I wanted to
68 * Redone as a library that can replace open, read, write, etc, by
69 * Fred Fish, with some additional work by Arnold Robbins.
72 /* Use -DUSE_REXEC for rexec code, courtesy of Dan Kegel, srs!dan */
74 #if defined(USG) && !defined(HAVE_MTIO)
80 #include <sys/types.h>
83 #include <sys/ioctl.h>
95 #define BUFMAGIC 64 /* a magic number for buffer sizes */
98 * MAXUNIT --- Maximum number of remote tape file units
103 * READ --- Return the number of the read side file descriptor
104 * WRITE --- Return the number of the write side file descriptor
106 #define READ(fd) (Ctp[fd][0])
107 #define WRITE(fd) (Ptc[fd][1])
109 static int Ctp
[MAXUNIT
][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
110 static int Ptc
[MAXUNIT
][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
117 * _rmt_panic --- close off a remote tape connection
120 static void _rmt_panic(fildes
)
124 close(WRITE(fildes
));
132 * command --- attempt to perform a remote tape command
135 static int command(fildes
, buf
)
147 * save current pipe status and try to make the request
151 pstat
= signal(SIGPIPE
, SIG_IGN
);
152 if (write(WRITE(fildes
), buf
, blen
) == blen
)
154 signal(SIGPIPE
, pstat
);
159 * something went wrong. close down and go home
162 signal(SIGPIPE
, pstat
);
172 * status --- retrieve the status from the pipe
175 static int status(fildes
)
180 char buffer
[BUFMAGIC
];
183 * read the reply command line
186 for (i
= 0, cp
= buffer
; i
< BUFMAGIC
; i
++, cp
++)
188 if (read(READ(fildes
), cp
, 1) != 1)
209 * check the return status
212 for (cp
= buffer
; *cp
; cp
++)
216 if (*cp
== 'E' || *cp
== 'F')
218 errno
= atoi(cp
+ 1);
219 while (read(READ(fildes
), &c
, 1) == 1)
230 * check for mis-synced pipes
240 return(atoi(cp
+ 1));
248 * execute /etc/rmt on a remote system using rexec().
249 * Return file descriptor of bidirectional socket for stdin and stdout
250 * If username is NULL, or an empty string, uses current username.
252 * ADR: By default, this code is not used, since it requires that
253 * the user have a .netrc file in his/her home directory, or that the
254 * application designer be willing to have rexec prompt for login and
255 * password info. This may be unacceptable, and .rhosts files for use
256 * with rsh are much more common on BSD systems.
260 _rmt_rexec(host
, user
)
262 char *user
; /* may be NULL */
264 struct servent
*rexecserv
;
265 int save_stdin
= dup(fileno(stdin
));
266 int save_stdout
= dup(fileno(stdout
));
267 int tape_fd
; /* Return value. */
270 * When using cpio -o < filename, stdin is no longer the tty.
271 * But the rexec subroutine reads the login and the passwd on stdin,
272 * to allow remote execution of the command.
273 * So, reopen stdin and stdout on /dev/tty before the rexec and
274 * give them back their original value after.
276 if (freopen("/dev/tty", "r", stdin
) == NULL
)
277 freopen("/dev/null", "r", stdin
);
278 if (freopen("/dev/tty", "w", stdout
) == NULL
)
279 freopen("/dev/null", "w", stdout
);
281 rexecserv
= getservbyname("exec", "tcp");
282 if (NULL
== rexecserv
) {
283 fprintf (stderr
, "? exec/tcp: service not available.");
286 if ((user
!= NULL
) && *user
== '\0')
287 user
= (char *) NULL
;
288 tape_fd
= rexec (&host
, rexecserv
->s_port
, user
, NULL
,
289 "/etc/rmt", (int *)NULL
);
291 fdopen(save_stdin
, "r");
293 fdopen(save_stdout
, "w");
297 #endif /* USE_REXEC */
300 * _rmt_open --- open a magtape device on system specified, as given user
302 * file name has the form [user@]system:/dev/????
304 * file name has the form system[.user]:/dev/????
308 #define MAXHOSTLEN 257 /* BSD allows very long host names... */
310 int __rmt_open (path
, oflag
, mode
, bias
)
317 char buffer
[BUFMAGIC
];
318 char system
[MAXHOSTLEN
];
319 char device
[BUFMAGIC
];
320 char login
[BUFMAGIC
];
321 char *sys
, *dev
, *user
;
328 * first, find an open pair of file descriptors
331 for (i
= 0; i
< MAXUNIT
; i
++)
332 if (READ(i
) == -1 && WRITE(i
) == -1)
342 * pull apart system and device, and optional user
343 * don't munge original string
344 * if COMPAT is defined, also handle old (4.2) style person.site notation.
357 if (*(path
- 1) == '@')
359 (void) strcpy (user
, system
); /* saw user part of user@host */
360 sys
= system
; /* start over */
361 while (*path
!= ':') {
368 else if (*(path
- 1) == '.')
370 while (*path
!= ':') {
387 * Execute the remote command using rexec
389 READ(i
) = WRITE(i
) = _rmt_rexec(system
, login
);
394 * setup the pipes for the 'rsh' command and fork
397 if (pipe(Ptc
[i
]) == -1 || pipe(Ctp
[i
]) == -1)
400 if ((rc
= fork()) == -1)
407 close(Ptc
[i
][0]); close(Ptc
[i
][1]);
410 close(Ctp
[i
][0]); close(Ctp
[i
][1]);
411 (void) setuid (getuid ());
412 (void) setgid (getgid ());
415 execl("/usr/ucb/rsh", "rsh", system
, "-l", login
,
416 "/etc/rmt", (char *) 0);
417 execl("/usr/bin/remsh", "remsh", system
, "-l", login
,
418 "/etc/rmt", (char *) 0);
419 execl("/usr/bin/rsh", "rsh", system
, "-l", login
,
420 "/etc/rmt", (char *) 0);
421 execl("/usr/bsd/rsh", "rsh", system
, "-l", login
,
422 "/etc/rmt", (char *)0);
423 execl("/usr/bin/nsh", "nsh", system
, "-l", login
,
424 "/etc/rmt", (char *)0);
428 execl("/usr/ucb/rsh", "rsh", system
,
429 "/etc/rmt", (char *) 0);
430 execl("/usr/bin/remsh", "remsh", system
,
431 "/etc/rmt", (char *) 0);
432 execl("/usr/bin/rsh", "rsh", system
,
433 "/etc/rmt", (char *) 0);
434 execl("/usr/bsd/rsh", "rsh", system
,
435 "/etc/rmt", (char *) 0);
436 execl("/usr/bin/nsh", "nsh", system
,
437 "/etc/rmt", (char *)0);
441 * bad problems if we get here
444 perror("remote shell exec");
448 close(Ptc
[i
][0]); close(Ctp
[i
][1]);
452 * now attempt to open the tape device
455 sprintf(buffer
, "O%s\n%d\n", device
, oflag
);
456 if (command(i
, buffer
) == -1 || status(i
) == -1)
465 * _rmt_close --- close a remote magtape unit and shut down
468 int __rmt_close(fildes
)
473 if (command(fildes
, "C\n") != -1)
487 * _rmt_read --- read a buffer from a remote tape
490 int __rmt_read(fildes
, buf
, nbyte
)
496 char buffer
[BUFMAGIC
];
498 sprintf(buffer
, "R%d\n", nbyte
);
499 if (command(fildes
, buffer
) == -1 || (rc
= status(fildes
)) == -1)
502 for (i
= 0; i
< rc
; i
+= nbyte
, buf
+= nbyte
)
504 nbyte
= read(READ(fildes
), buf
, rc
);
519 * _rmt_write --- write a buffer to the remote tape
522 int __rmt_write(fildes
, buf
, nbyte
)
527 char buffer
[BUFMAGIC
];
534 sprintf(buffer
, "W%d\n", nbyte
);
535 if (command(fildes
, buffer
) == -1)
538 pstat
= signal(SIGPIPE
, SIG_IGN
);
539 if (write(WRITE(fildes
), buf
, nbyte
) == nbyte
)
541 signal (SIGPIPE
, pstat
);
542 return(status(fildes
));
545 signal (SIGPIPE
, pstat
);
554 * _rmt_lseek --- perform an imitation lseek operation remotely
557 long __rmt_lseek(fildes
, offset
, whence
)
562 char buffer
[BUFMAGIC
];
564 sprintf(buffer
, "L%d\n%d\n", offset
, whence
);
565 if (command(fildes
, buffer
) == -1)
568 return(status(fildes
));
573 * _rmt_ioctl --- perform raw tape operations remotely
577 __rmt_ioctl(fildes
, op
, arg
)
583 char buffer
[BUFMAGIC
];
586 * MTIOCOP is the easy one. nothing is transfered in binary
591 sprintf(buffer
, "I%d\n%d\n", ((struct mtop
*) arg
)->mt_op
,
592 ((struct mtop
*) arg
)->mt_count
);
593 if (command(fildes
, buffer
) == -1)
595 return(status(fildes
));
599 * we can only handle 2 ops, if not the other one, punt
609 * grab the status and read it directly into the structure
610 * this assumes that the status buffer is (hopefully) not
611 * padded and that 2 shorts fit in a long without any word
612 * alignment problems, ie - the whole struct is contiguous
613 * NOTE - this is probably NOT a good assumption.
616 if (command(fildes
, "S") == -1 || (rc
= status(fildes
)) == -1)
619 for (; rc
> 0; rc
-= cnt
, arg
+= cnt
)
621 cnt
= read(READ(fildes
), arg
, rc
);
631 * now we check for byte position. mt_type is a small integer field
632 * (normally) so we will check its magnitude. if it is larger than
633 * 256, we will assume that the bytes are swapped and go through
634 * and reverse all the bytes
637 if (((struct mtget
*) arg
)->mt_type
< 256)
640 for (cnt
= 0; cnt
< rc
; cnt
+= 2)
643 arg
[cnt
] = arg
[cnt
+1];
649 #endif /* NO_RMTIOCTL */