]>
Dogcows Code - chaz/tar/blob - src/rtapelib.c
1 /* Functions for communicating with a remote tape drive.
2 Copyright (C) 1988, 1992, 1994, 1996 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol
19 which rdump and rrestore use. Unfortunately, the man page is *WRONG*.
20 The author of the routines I'm including originally wrote his code just
21 based on the man page, and it didn't work, so he went to the rdump source
22 to figure out why. The only thing he had to change was to check for the
23 'F' return code in addition to the 'E', and to separate the various
24 arguments with \n instead of a space. I personally don't think that this
25 is much of a problem, but I wanted to point it out. -- Arnold Robbins
27 Originally written by Jeff Lee, modified some by Arnold Robbins. Redone
28 as a library that can replace open, read, write, etc., by Fred Fish, with
29 some additional work by Arnold Robbins. Modified to make all rmt* calls
30 into macros for speed by Jay Fenlason. Use -DHAVE_NETDB_H for rexec
31 code, courtesy of Dan Kegel. */
35 /* Try hard to get EOPNOTSUPP defined. 486/ISC has it in net/errno.h,
36 3B2/SVR3 has it in sys/inet.h. Otherwise, like on MSDOS, use EINVAL. */
40 # include <net/errno.h>
43 # include <sys/inet.h>
46 # define EOPNOTSUPP EINVAL
58 /* FIXME: Just to shut up -Wall. */
61 /* Exit status if exec errors. */
62 #define EXIT_ON_EXEC_ERROR 128
64 /* FIXME: Size of buffers for reading and writing commands to rmt. */
65 #define COMMAND_BUFFER_SIZE 64
68 # define RETSIGTYPE void
71 /* FIXME: Maximum number of simultaneous remote tape connections. */
74 #define PREAD 0 /* read file descriptor from pipe() */
75 #define PWRITE 1 /* write file descriptor from pipe() */
77 /* Return the parent's read side of remote tape connection Fd. */
78 #define READ_SIDE(Fd) (from_remote[Fd][PREAD])
80 /* Return the parent's write side of remote tape connection Fd. */
81 #define WRITE_SIDE(Fd) (to_remote[Fd][PWRITE])
83 /* The pipes for receiving data from remote tape drives. */
84 static int from_remote
[MAXUNIT
][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
86 /* The pipes for sending data to remote tape drives. */
87 static int to_remote
[MAXUNIT
][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
89 /* Temporary variable used by macros in rmt.h. */
93 /*----------------------------------------------------------------------.
94 | Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE. |
95 `----------------------------------------------------------------------*/
98 _rmt_shutdown (int handle
, int errno_value
)
100 close (READ_SIDE (handle
));
101 close (WRITE_SIDE (handle
));
102 READ_SIDE (handle
) = -1;
103 WRITE_SIDE (handle
) = -1;
104 errno
= errno_value
; /* FIXME: errno should be read-only */
107 /*-------------------------------------------------------------------------.
108 | Attempt to perform the remote tape command specified in BUFFER on remote |
109 | tape connection HANDLE. Return 0 if successful, -1 on error. |
110 `-------------------------------------------------------------------------*/
113 do_command (int handle
, const char *buffer
)
116 RETSIGTYPE (*pipe_handler
) ();
118 /* Save the current pipe handler and try to make the request. */
120 pipe_handler
= signal (SIGPIPE
, SIG_IGN
);
121 length
= strlen (buffer
);
122 if (write (WRITE_SIDE (handle
), buffer
, (size_t) length
) == length
)
124 signal (SIGPIPE
, pipe_handler
);
128 /* Something went wrong. Close down and go home. */
130 signal (SIGPIPE
, pipe_handler
);
131 _rmt_shutdown (handle
, EIO
);
135 /*----------------------------------------------------------------------.
136 | Read and return the status from remote tape connection HANDLE. If an |
137 | error occurred, return -1 and set errno. |
138 `----------------------------------------------------------------------*/
141 get_status (int handle
)
143 char command_buffer
[COMMAND_BUFFER_SIZE
];
147 /* Read the reply command line. */
149 for (counter
= 0, cursor
= command_buffer
;
150 counter
< COMMAND_BUFFER_SIZE
;
153 if (read (READ_SIDE (handle
), cursor
, 1) != 1)
155 _rmt_shutdown (handle
, EIO
);
165 if (counter
== COMMAND_BUFFER_SIZE
)
167 _rmt_shutdown (handle
, EIO
);
171 /* Check the return status. */
173 for (cursor
= command_buffer
; *cursor
; cursor
++)
177 if (*cursor
== 'E' || *cursor
== 'F')
179 errno
= atoi (cursor
+ 1); /* FIXME: errno should be read-only */
181 /* Skip the error message line. */
183 /* FIXME: there is better to do than merely ignoring error messages
184 coming from the remote end. Translate them, too... */
189 while (read (READ_SIDE (handle
), &character
, 1) == 1)
190 if (character
== '\n')
195 _rmt_shutdown (handle
, errno
);
200 /* Check for mis-synced pipes. */
204 _rmt_shutdown (handle
, EIO
);
208 /* Got an `A' (success) response. */
210 return atoi (cursor
+ 1);
215 /*-------------------------------------------------------------------------.
216 | Execute /etc/rmt as user USER on remote system HOST using rexec. Return |
217 | a file descriptor of a bidirectional socket for stdin and stdout. If |
218 | USER is NULL, use the current username. |
220 | By default, this code is not used, since it requires that the user have |
221 | a .netrc file in his/her home directory, or that the application |
222 | designer be willing to have rexec prompt for login and password info. |
223 | This may be unacceptable, and .rhosts files for use with rsh are much |
224 | more common on BSD systems. |
225 `-------------------------------------------------------------------------*/
228 _rmt_rexec (char *host
, char *user
)
230 int saved_stdin
= dup (fileno (stdin
));
231 int saved_stdout
= dup (fileno (stdout
));
232 struct servent
*rexecserv
;
235 /* When using cpio -o < filename, stdin is no longer the tty. But the
236 rexec subroutine reads the login and the passwd on stdin, to allow
237 remote execution of the command. So, reopen stdin and stdout on
238 /dev/tty before the rexec and give them back their original value
241 if (freopen ("/dev/tty", "r", stdin
) == NULL
)
242 freopen ("/dev/null", "r", stdin
);
243 if (freopen ("/dev/tty", "w", stdout
) == NULL
)
244 freopen ("/dev/null", "w", stdout
);
246 if (rexecserv
= getservbyname ("exec", "tcp"), !rexecserv
)
247 error (EXIT_ON_EXEC_ERROR
, 0, _("exec/tcp: Service not available"));
249 result
= rexec (&host
, rexecserv
->s_port
, user
, NULL
,
250 "/etc/rmt", (int *) NULL
);
251 if (fclose (stdin
) == EOF
)
252 error (0, errno
, _("stdin"));
253 fdopen (saved_stdin
, "r");
254 if (fclose (stdout
) == EOF
)
255 error (0, errno
, _("stdout"));
256 fdopen (saved_stdout
, "w");
261 #endif /* HAVE_NETDB_H */
263 /*------------------------------------------------------------------------.
264 | Open a file (a magnetic tape device?) on the system specified in PATH, |
265 | as the given user. PATH has the form `[USER@]HOST:FILE'. OPEN_MODE is |
266 | O_RDONLY, O_WRONLY, etc. If successful, return the remote pipe number |
267 | plus BIAS. REMOTE_SHELL may be overriden. On error, return -1. |
268 `------------------------------------------------------------------------*/
271 rmt_open__ (const char *path
, int open_mode
, int bias
, const char *remote_shell
)
273 int remote_pipe_number
; /* pseudo, biased file descriptor */
274 char *path_copy
; /* copy of path string */
275 char *remote_host
; /* remote host name */
276 char *remote_file
; /* remote file name (often a device) */
277 char *remote_user
; /* remote user name */
279 /* Find an unused pair of file descriptors. */
281 for (remote_pipe_number
= 0;
282 remote_pipe_number
< MAXUNIT
;
283 remote_pipe_number
++)
284 if (READ_SIDE (remote_pipe_number
) == -1
285 && WRITE_SIDE (remote_pipe_number
) == -1)
288 if (remote_pipe_number
== MAXUNIT
)
290 errno
= EMFILE
; /* FIXME: errno should be read-only */
294 /* Pull apart the system and device, and optional user. */
299 path_copy
= xstrdup (path
);
300 remote_host
= path_copy
;
304 for (cursor
= path_copy
; *cursor
; cursor
++)
313 remote_user
= remote_host
;
315 remote_host
= cursor
+ 1;
323 remote_file
= cursor
+ 1;
329 /* FIXME: Should somewhat validate the decoding, here. */
331 if (remote_user
&& *remote_user
== '\0')
336 /* Execute the remote command using rexec. */
338 READ_SIDE (remote_pipe_number
) = _rmt_rexec (remote_host
, remote_user
);
339 if (READ_SIDE (remote_pipe_number
) < 0)
345 WRITE_SIDE (remote_pipe_number
) = READ_SIDE (remote_pipe_number
);
347 #else /* not HAVE_NETDB_H */
349 const char *remote_shell_basename
;
352 /* Identify the remote command to be executed. */
357 remote_shell
= REMOTE_SHELL
;
359 errno
= EIO
; /* FIXME: errno should be read-only */
364 remote_shell_basename
= strrchr (remote_shell
, '/');
365 if (remote_shell_basename
)
366 remote_shell_basename
++;
368 remote_shell_basename
= remote_shell
;
370 /* Set up the pipes for the `rsh' command, and fork. */
372 if (pipe (to_remote
[remote_pipe_number
]) == -1
373 || pipe (from_remote
[remote_pipe_number
]) == -1)
391 dup (to_remote
[remote_pipe_number
][PREAD
]);
392 close (to_remote
[remote_pipe_number
][PREAD
]);
393 close (to_remote
[remote_pipe_number
][PWRITE
]);
396 dup (from_remote
[remote_pipe_number
][PWRITE
]);
397 close (from_remote
[remote_pipe_number
][PREAD
]);
398 close (from_remote
[remote_pipe_number
][PWRITE
]);
406 execl (remote_shell
, remote_shell_basename
, remote_host
,
407 "-l", remote_user
, "/etc/rmt", (char *) 0);
409 execl (remote_shell
, remote_shell_basename
, remote_host
,
410 "/etc/rmt", (char *) 0);
412 /* Bad problems if we get here. */
414 /* In a previous version, _exit was used here instead of exit. */
415 error (EXIT_ON_EXEC_ERROR
, errno
, _("Cannot execute remote shell"));
420 close (from_remote
[remote_pipe_number
][PWRITE
]);
421 close (to_remote
[remote_pipe_number
][PREAD
]);
423 #endif /* not HAVE_NETDB_H */
425 /* Attempt to open the tape device. */
428 char command_buffer
[COMMAND_BUFFER_SIZE
];
430 sprintf (command_buffer
, "O%s\n%d\n", remote_file
, open_mode
);
431 if (do_command (remote_pipe_number
, command_buffer
) == -1
432 || get_status (remote_pipe_number
) == -1)
434 _rmt_shutdown (remote_pipe_number
, errno
);
441 return remote_pipe_number
+ bias
;
444 /*----------------------------------------------------------------.
445 | Close remote tape connection HANDLE and shut down. Return 0 if |
446 | successful, -1 on error. |
447 `----------------------------------------------------------------*/
450 rmt_close__ (int handle
)
454 if (do_command (handle
, "C\n") == -1)
457 status
= get_status (handle
);
458 _rmt_shutdown (handle
, errno
);
462 /*-------------------------------------------------------------------------.
463 | Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE. |
464 | Return the number of bytes read on success, -1 on error. |
465 `-------------------------------------------------------------------------*/
468 rmt_read__ (int handle
, char *buffer
, unsigned int length
)
470 char command_buffer
[COMMAND_BUFFER_SIZE
];
474 sprintf (command_buffer
, "R%d\n", length
);
475 if (do_command (handle
, command_buffer
) == -1
476 || (status
= get_status (handle
)) == -1)
479 for (counter
= 0; counter
< status
; counter
+= length
, buffer
+= length
)
481 length
= read (READ_SIDE (handle
), buffer
, (size_t) (status
- counter
));
484 _rmt_shutdown (handle
, EIO
);
492 /*-------------------------------------------------------------------------.
493 | Write LENGTH bytes from BUFFER to remote tape connection HANDLE. Return |
494 | the number of bytes written on success, -1 on error. |
495 `-------------------------------------------------------------------------*/
498 rmt_write__ (int handle
, char *buffer
, unsigned int length
)
500 char command_buffer
[COMMAND_BUFFER_SIZE
];
501 RETSIGTYPE (*pipe_handler
) ();
503 sprintf (command_buffer
, "W%d\n", length
);
504 if (do_command (handle
, command_buffer
) == -1)
507 pipe_handler
= signal (SIGPIPE
, SIG_IGN
);
508 if (write (WRITE_SIDE (handle
), buffer
, length
) == length
)
510 signal (SIGPIPE
, pipe_handler
);
511 return get_status (handle
);
516 signal (SIGPIPE
, pipe_handler
);
517 _rmt_shutdown (handle
, EIO
);
521 /*------------------------------------------------------------------------.
522 | Perform an imitation lseek operation on remote tape connection HANDLE. |
523 | Return the new file offset if successful, -1 if on error. |
524 `------------------------------------------------------------------------*/
527 rmt_lseek__ (int handle
, off_t offset
, int whence
)
529 char command_buffer
[COMMAND_BUFFER_SIZE
];
531 sprintf (command_buffer
, "L%ld\n%d\n", offset
, whence
);
532 if (do_command (handle
, command_buffer
) == -1)
535 return get_status (handle
);
538 /*-----------------------------------------------------------------------.
539 | Perform a raw tape operation on remote tape connection HANDLE. Return |
540 | the results of the ioctl, or -1 on error. |
541 `-----------------------------------------------------------------------*/
544 rmt_ioctl__ (int handle
, int operation
, char *argument
)
549 errno
= EOPNOTSUPP
; /* FIXME: errno should be read-only */
555 char command_buffer
[COMMAND_BUFFER_SIZE
];
557 /* MTIOCTOP is the easy one. Nothing is transfered in binary. */
559 sprintf (command_buffer
, "I%d\n%d\n", ((struct mtop
*) argument
)->mt_op
,
560 ((struct mtop
*) argument
)->mt_count
);
561 if (do_command (handle
, command_buffer
) == -1)
564 /* Return the count. */
566 return get_status (handle
);
568 #endif /* MTIOCTOP */
576 /* Grab the status and read it directly into the structure. This
577 assumes that the status buffer is not padded and that 2 shorts
578 fit in a long without any word alignment problems; i.e., the
579 whole struct is contiguous. NOTE - this is probably NOT a good
582 if (do_command (handle
, "S") == -1
583 || (status
= get_status (handle
), status
== -1))
586 for (; status
> 0; status
-= counter
, argument
+= counter
)
588 counter
= read (READ_SIDE (handle
), argument
, (size_t) status
);
591 _rmt_shutdown (handle
, EIO
);
596 /* Check for byte position. mt_type (or mt_model) is a small integer
597 field (normally) so we will check its magnitude. If it is larger
598 than 256, we will assume that the bytes are swapped and go through
599 and reverse all the bytes. */
601 if (((struct mtget
*) argument
)->MTIO_CHECK_FIELD
< 256)
604 for (counter
= 0; counter
< status
; counter
+= 2)
606 char copy
= argument
[counter
];
608 argument
[counter
] = argument
[counter
+ 1];
609 argument
[counter
+ 1] = copy
;
614 #endif /* MTIOCGET */
This page took 0.062756 seconds and 4 git commands to generate.