No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / usr.bin / tar / rtape_lib.c
blob2e91e5a8b97351f206accf0b788a0ca2e02891ff
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)
9 any later version.
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 */
22 #ifndef lint
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 $";
24 #endif
27 * $Log: rmtlib.c,v $
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
48 * Initial revision
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
65 * point it out.
66 * -- Arnold Robbins
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)
75 #define NO_RMTIOCTL
76 #endif
78 #include <stdio.h>
79 #include <signal.h>
80 #include <sys/types.h>
82 #ifndef NO_RMTIOCTL
83 #include <sys/ioctl.h>
84 #include <sys/mtio.h>
85 #endif
87 #ifdef USE_REXEC
88 #include <netdb.h>
89 #endif
91 #include <errno.h>
92 #include <setjmp.h>
93 #include <sys/stat.h>
95 #define BUFMAGIC 64 /* a magic number for buffer sizes */
98 * MAXUNIT --- Maximum number of remote tape file units
100 #define MAXUNIT 4
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 };
112 extern int errno;
114 char *__rmt_path;
117 * _rmt_panic --- close off a remote tape connection
120 static void _rmt_panic(fildes)
121 int fildes;
123 close(READ(fildes));
124 close(WRITE(fildes));
125 READ(fildes) = -1;
126 WRITE(fildes) = -1;
132 * command --- attempt to perform a remote tape command
135 static int command(fildes, buf)
136 int fildes;
137 char *buf;
139 register int blen;
140 #ifdef SIGNAL_VOID
141 void (*pstat)();
142 #else
143 int (*pstat)();
144 #endif
147 * save current pipe status and try to make the request
150 blen = strlen(buf);
151 pstat = signal(SIGPIPE, SIG_IGN);
152 if (write(WRITE(fildes), buf, blen) == blen)
154 signal(SIGPIPE, pstat);
155 return(0);
159 * something went wrong. close down and go home
162 signal(SIGPIPE, pstat);
163 _rmt_panic(fildes);
165 errno = EIO;
166 return(-1);
172 * status --- retrieve the status from the pipe
175 static int status(fildes)
176 int fildes;
178 int i;
179 char c, *cp;
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)
190 _rmt_panic(fildes);
191 errno = EIO;
192 return(-1);
194 if (*cp == '\n')
196 *cp = 0;
197 break;
201 if (i == BUFMAGIC)
203 _rmt_panic(fildes);
204 errno = EIO;
205 return(-1);
209 * check the return status
212 for (cp = buffer; *cp; cp++)
213 if (*cp != ' ')
214 break;
216 if (*cp == 'E' || *cp == 'F')
218 errno = atoi(cp + 1);
219 while (read(READ(fildes), &c, 1) == 1)
220 if (c == '\n')
221 break;
223 if (*cp == 'F')
224 _rmt_panic(fildes);
226 return(-1);
230 * check for mis-synced pipes
233 if (*cp != 'A')
235 _rmt_panic(fildes);
236 errno = EIO;
237 return(-1);
240 return(atoi(cp + 1));
243 #ifdef USE_REXEC
246 * _rmt_rexec
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.
259 static int
260 _rmt_rexec(host, user)
261 char *host;
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.");
284 exit (-1);
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);
290 fclose(stdin);
291 fdopen(save_stdin, "r");
292 fclose(stdout);
293 fdopen(save_stdout, "w");
295 return tape_fd;
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/????
303 #ifdef COMPAT
304 * file name has the form system[.user]:/dev/????
305 #endif
308 #define MAXHOSTLEN 257 /* BSD allows very long host names... */
310 int __rmt_open (path, oflag, mode, bias)
311 char *path;
312 int oflag;
313 int mode;
314 int bias;
316 int i, rc;
317 char buffer[BUFMAGIC];
318 char system[MAXHOSTLEN];
319 char device[BUFMAGIC];
320 char login[BUFMAGIC];
321 char *sys, *dev, *user;
323 sys = system;
324 dev = device;
325 user = login;
328 * first, find an open pair of file descriptors
331 for (i = 0; i < MAXUNIT; i++)
332 if (READ(i) == -1 && WRITE(i) == -1)
333 break;
335 if (i == MAXUNIT)
337 errno = EMFILE;
338 return(-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.
347 while (*path != '@'
348 #ifdef COMPAT
349 && *path != '.'
350 #endif
351 && *path != ':') {
352 *sys++ = *path++;
354 *sys = '\0';
355 path++;
357 if (*(path - 1) == '@')
359 (void) strcpy (user, system); /* saw user part of user@host */
360 sys = system; /* start over */
361 while (*path != ':') {
362 *sys++ = *path++;
364 *sys = '\0';
365 path++;
367 #ifdef COMPAT
368 else if (*(path - 1) == '.')
370 while (*path != ':') {
371 *user++ = *path++;
373 *user = '\0';
374 path++;
376 #endif
377 else
378 *user = '\0';
380 while (*path) {
381 *dev++ = *path++;
383 *dev = '\0';
385 #ifdef USE_REXEC
387 * Execute the remote command using rexec
389 READ(i) = WRITE(i) = _rmt_rexec(system, login);
390 if (READ(i) < 0)
391 return -1;
392 #else
394 * setup the pipes for the 'rsh' command and fork
397 if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
398 return(-1);
400 if ((rc = fork()) == -1)
401 return(-1);
403 if (rc == 0)
405 close(0);
406 dup(Ptc[i][0]);
407 close(Ptc[i][0]); close(Ptc[i][1]);
408 close(1);
409 dup(Ctp[i][1]);
410 close(Ctp[i][0]); close(Ctp[i][1]);
411 (void) setuid (getuid ());
412 (void) setgid (getgid ());
413 if (*login)
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);
426 else
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");
445 exit(1);
448 close(Ptc[i][0]); close(Ctp[i][1]);
449 #endif
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)
457 return(-1);
459 return(i+bias);
465 * _rmt_close --- close a remote magtape unit and shut down
468 int __rmt_close(fildes)
469 int fildes;
471 int rc;
473 if (command(fildes, "C\n") != -1)
475 rc = status(fildes);
477 _rmt_panic(fildes);
478 return(rc);
481 return(-1);
487 * _rmt_read --- read a buffer from a remote tape
490 int __rmt_read(fildes, buf, nbyte)
491 int fildes;
492 char *buf;
493 unsigned int nbyte;
495 int rc, i;
496 char buffer[BUFMAGIC];
498 sprintf(buffer, "R%d\n", nbyte);
499 if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
500 return(-1);
502 for (i = 0; i < rc; i += nbyte, buf += nbyte)
504 nbyte = read(READ(fildes), buf, rc);
505 if (nbyte <= 0)
507 _rmt_panic(fildes);
508 errno = EIO;
509 return(-1);
513 return(rc);
519 * _rmt_write --- write a buffer to the remote tape
522 int __rmt_write(fildes, buf, nbyte)
523 int fildes;
524 char *buf;
525 unsigned int nbyte;
527 char buffer[BUFMAGIC];
528 #ifdef SIGNAL_VOID
529 void (*pstat)();
530 #else
531 int (*pstat)();
532 #endif
534 sprintf(buffer, "W%d\n", nbyte);
535 if (command(fildes, buffer) == -1)
536 return(-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);
546 _rmt_panic(fildes);
547 errno = EIO;
548 return(-1);
554 * _rmt_lseek --- perform an imitation lseek operation remotely
557 long __rmt_lseek(fildes, offset, whence)
558 int fildes;
559 long offset;
560 int whence;
562 char buffer[BUFMAGIC];
564 sprintf(buffer, "L%d\n%d\n", offset, whence);
565 if (command(fildes, buffer) == -1)
566 return(-1);
568 return(status(fildes));
573 * _rmt_ioctl --- perform raw tape operations remotely
576 #ifndef NO_RMTIOCTL
577 __rmt_ioctl(fildes, op, arg)
578 int fildes, op;
579 char *arg;
581 char c;
582 int rc, cnt;
583 char buffer[BUFMAGIC];
586 * MTIOCOP is the easy one. nothing is transfered in binary
589 if (op == MTIOCTOP)
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)
594 return(-1);
595 return(status(fildes));
599 * we can only handle 2 ops, if not the other one, punt
602 if (op != MTIOCGET)
604 errno = EINVAL;
605 return(-1);
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)
617 return(-1);
619 for (; rc > 0; rc -= cnt, arg += cnt)
621 cnt = read(READ(fildes), arg, rc);
622 if (cnt <= 0)
624 _rmt_panic(fildes);
625 errno = EIO;
626 return(-1);
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)
638 return(0);
640 for (cnt = 0; cnt < rc; cnt += 2)
642 c = arg[cnt];
643 arg[cnt] = arg[cnt+1];
644 arg[cnt+1] = c;
647 return(0);
649 #endif /* NO_RMTIOCTL */