summaryrefslogtreecommitdiffstats
path: root/contrib/cpio/lib/rtapelib.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cpio/lib/rtapelib.c')
-rw-r--r--contrib/cpio/lib/rtapelib.c741
1 files changed, 0 insertions, 741 deletions
diff --git a/contrib/cpio/lib/rtapelib.c b/contrib/cpio/lib/rtapelib.c
deleted file mode 100644
index d73d136..0000000
--- a/contrib/cpio/lib/rtapelib.c
+++ /dev/null
@@ -1,741 +0,0 @@
-/* Functions for communicating with a remote tape drive.
-
- Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2004,
- 2005, 2006 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
-
-/* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol
- which rdump and rrestore use. Unfortunately, the man page is *WRONG*.
- The author of the routines I'm including originally wrote his code just
- based on the man page, and it didn't work, so he went to the rdump source
- to figure out why. The only thing he had to change was to check for the
- 'F' return code in addition to the 'E', and to separate the various
- arguments with \n instead of a space. I personally don't think that this
- is much of a problem, but I wanted to point it out. -- Arnold Robbins
-
- Originally written by Jeff Lee, modified some by Arnold Robbins. Redone
- as a library that can replace open, read, write, etc., by Fred Fish, with
- some additional work by Arnold Robbins. Modified to make all rmt* calls
- into macros for speed by Jay Fenlason. Use -DWITH_REXEC for rexec
- code, courtesy of Dan Kegel. */
-
-#include "system.h"
-#include "system-ioctl.h"
-
-#include <safe-read.h>
-#include <full-write.h>
-
-/* Try hard to get EOPNOTSUPP defined. 486/ISC has it in net/errno.h,
- 3B2/SVR3 has it in sys/inet.h. Otherwise, like on MSDOS, use EINVAL. */
-
-#ifndef EOPNOTSUPP
-# if HAVE_NET_ERRNO_H
-# include <net/errno.h>
-# endif
-# if HAVE_SYS_INET_H
-# include <sys/inet.h>
-# endif
-# ifndef EOPNOTSUPP
-# define EOPNOTSUPP EINVAL
-# endif
-#endif
-
-#include <signal.h>
-
-#if HAVE_NETDB_H
-# include <netdb.h>
-#endif
-
-#include <rmt.h>
-#include <rmt-command.h>
-
-/* Exit status if exec errors. */
-#define EXIT_ON_EXEC_ERROR 128
-
-/* FIXME: Size of buffers for reading and writing commands to rmt. */
-#define COMMAND_BUFFER_SIZE 64
-
-#ifndef RETSIGTYPE
-# define RETSIGTYPE void
-#endif
-
-/* FIXME: Maximum number of simultaneous remote tape connections. */
-#define MAXUNIT 4
-
-#define PREAD 0 /* read file descriptor from pipe() */
-#define PWRITE 1 /* write file descriptor from pipe() */
-
-/* Return the parent's read side of remote tape connection Fd. */
-#define READ_SIDE(Fd) (from_remote[Fd][PREAD])
-
-/* Return the parent's write side of remote tape connection Fd. */
-#define WRITE_SIDE(Fd) (to_remote[Fd][PWRITE])
-
-/* The pipes for receiving data from remote tape drives. */
-static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
-
-/* The pipes for sending data to remote tape drives. */
-static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
-
-char *rmt_command = DEFAULT_RMT_COMMAND;
-
-/* Temporary variable used by macros in rmt.h. */
-char *rmt_dev_name__;
-
-/* If true, always consider file names to be local, even if they contain
- colons */
-bool force_local_option;
-
-
-
-/* Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE. */
-static void
-_rmt_shutdown (int handle, int errno_value)
-{
- close (READ_SIDE (handle));
- close (WRITE_SIDE (handle));
- READ_SIDE (handle) = -1;
- WRITE_SIDE (handle) = -1;
- errno = errno_value;
-}
-
-/* Attempt to perform the remote tape command specified in BUFFER on
- remote tape connection HANDLE. Return 0 if successful, -1 on
- error. */
-static int
-do_command (int handle, const char *buffer)
-{
- /* Save the current pipe handler and try to make the request. */
-
- size_t length = strlen (buffer);
- RETSIGTYPE (*pipe_handler) () = signal (SIGPIPE, SIG_IGN);
- ssize_t written = full_write (WRITE_SIDE (handle), buffer, length);
- signal (SIGPIPE, pipe_handler);
-
- if (written == length)
- return 0;
-
- /* Something went wrong. Close down and go home. */
-
- _rmt_shutdown (handle, EIO);
- return -1;
-}
-
-static char *
-get_status_string (int handle, char *command_buffer)
-{
- char *cursor;
- int counter;
-
- /* Read the reply command line. */
-
- for (counter = 0, cursor = command_buffer;
- counter < COMMAND_BUFFER_SIZE;
- counter++, cursor++)
- {
- if (safe_read (READ_SIDE (handle), cursor, 1) != 1)
- {
- _rmt_shutdown (handle, EIO);
- return 0;
- }
- if (*cursor == '\n')
- {
- *cursor = '\0';
- break;
- }
- }
-
- if (counter == COMMAND_BUFFER_SIZE)
- {
- _rmt_shutdown (handle, EIO);
- return 0;
- }
-
- /* Check the return status. */
-
- for (cursor = command_buffer; *cursor; cursor++)
- if (*cursor != ' ')
- break;
-
- if (*cursor == 'E' || *cursor == 'F')
- {
- /* Skip the error message line. */
-
- /* FIXME: there is better to do than merely ignoring error messages
- coming from the remote end. Translate them, too... */
-
- {
- char character;
-
- while (safe_read (READ_SIDE (handle), &character, 1) == 1)
- if (character == '\n')
- break;
- }
-
- errno = atoi (cursor + 1);
-
- if (*cursor == 'F')
- _rmt_shutdown (handle, errno);
-
- return 0;
- }
-
- /* Check for mis-synced pipes. */
-
- if (*cursor != 'A')
- {
- _rmt_shutdown (handle, EIO);
- return 0;
- }
-
- /* Got an `A' (success) response. */
-
- return cursor + 1;
-}
-
-/* Read and return the status from remote tape connection HANDLE. If
- an error occurred, return -1 and set errno. */
-static long int
-get_status (int handle)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- const char *status = get_status_string (handle, command_buffer);
- if (status)
- {
- long int result = atol (status);
- if (0 <= result)
- return result;
- errno = EIO;
- }
- return -1;
-}
-
-static off_t
-get_status_off (int handle)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- const char *status = get_status_string (handle, command_buffer);
-
- if (! status)
- return -1;
- else
- {
- /* Parse status, taking care to check for overflow.
- We can't use standard functions,
- since off_t might be longer than long. */
-
- off_t count = 0;
- int negative;
-
- for (; *status == ' ' || *status == '\t'; status++)
- continue;
-
- negative = *status == '-';
- status += negative || *status == '+';
-
- for (;;)
- {
- int digit = *status++ - '0';
- if (9 < (unsigned) digit)
- break;
- else
- {
- off_t c10 = 10 * count;
- off_t nc = negative ? c10 - digit : c10 + digit;
- if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
- return -1;
- count = nc;
- }
- }
-
- return count;
- }
-}
-
-#if WITH_REXEC
-
-/* Execute /etc/rmt as user USER on remote system HOST using rexec.
- Return a file descriptor of a bidirectional socket for stdin and
- stdout. If USER is zero, use the current username.
-
- By default, this code is not used, since it requires that the user
- have a .netrc file in his/her home directory, or that the
- application designer be willing to have rexec prompt for login and
- password info. This may be unacceptable, and .rhosts files for use
- with rsh are much more common on BSD systems. */
-static int
-_rmt_rexec (char *host, char *user)
-{
- int saved_stdin = dup (STDIN_FILENO);
- int saved_stdout = dup (STDOUT_FILENO);
- struct servent *rexecserv;
- int result;
-
- /* When using cpio -o < filename, stdin is no longer the tty. But the
- rexec subroutine reads the login and the passwd on stdin, to allow
- remote execution of the command. So, reopen stdin and stdout on
- /dev/tty before the rexec and give them back their original value
- after. */
-
- if (! freopen ("/dev/tty", "r", stdin))
- freopen ("/dev/null", "r", stdin);
- if (! freopen ("/dev/tty", "w", stdout))
- freopen ("/dev/null", "w", stdout);
-
- if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
- error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
-
- result = rexec (&host, rexecserv->s_port, user, 0, rmt_command, 0);
- if (fclose (stdin) == EOF)
- error (0, errno, _("stdin"));
- fdopen (saved_stdin, "r");
- if (fclose (stdout) == EOF)
- error (0, errno, _("stdout"));
- fdopen (saved_stdout, "w");
-
- return result;
-}
-
-#endif /* WITH_REXEC */
-
-/* Place into BUF a string representing OFLAG, which must be suitable
- as argument 2 of `open'. BUF must be large enough to hold the
- result. This function should generate a string that decode_oflag
- can parse. */
-static void
-encode_oflag (char *buf, int oflag)
-{
- sprintf (buf, "%d ", oflag);
-
- switch (oflag & O_ACCMODE)
- {
- case O_RDONLY: strcat (buf, "O_RDONLY"); break;
- case O_RDWR: strcat (buf, "O_RDWR"); break;
- case O_WRONLY: strcat (buf, "O_WRONLY"); break;
- default: abort ();
- }
-
-#ifdef O_APPEND
- if (oflag & O_APPEND) strcat (buf, "|O_APPEND");
-#endif
- if (oflag & O_CREAT) strcat (buf, "|O_CREAT");
-#ifdef O_DSYNC
- if (oflag & O_DSYNC) strcat (buf, "|O_DSYNC");
-#endif
- if (oflag & O_EXCL) strcat (buf, "|O_EXCL");
-#ifdef O_LARGEFILE
- if (oflag & O_LARGEFILE) strcat (buf, "|O_LARGEFILE");
-#endif
-#ifdef O_NOCTTY
- if (oflag & O_NOCTTY) strcat (buf, "|O_NOCTTY");
-#endif
- if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK");
-#ifdef O_RSYNC
- if (oflag & O_RSYNC) strcat (buf, "|O_RSYNC");
-#endif
-#ifdef O_SYNC
- if (oflag & O_SYNC) strcat (buf, "|O_SYNC");
-#endif
- if (oflag & O_TRUNC) strcat (buf, "|O_TRUNC");
-}
-
-/* Open a file (a magnetic tape device?) on the system specified in
- FILE_NAME, as the given user. FILE_NAME has the form `[USER@]HOST:FILE'.
- OPEN_MODE is O_RDONLY, O_WRONLY, etc. If successful, return the
- remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On
- error, return -1. */
-int
-rmt_open__ (const char *file_name, int open_mode, int bias,
- const char *remote_shell)
-{
- int remote_pipe_number; /* pseudo, biased file descriptor */
- char *file_name_copy; /* copy of file_name string */
- char *remote_host; /* remote host name */
- char *remote_file; /* remote file name (often a device) */
- char *remote_user; /* remote user name */
-
- /* Find an unused pair of file descriptors. */
-
- for (remote_pipe_number = 0;
- remote_pipe_number < MAXUNIT;
- remote_pipe_number++)
- if (READ_SIDE (remote_pipe_number) == -1
- && WRITE_SIDE (remote_pipe_number) == -1)
- break;
-
- if (remote_pipe_number == MAXUNIT)
- {
- errno = EMFILE;
- return -1;
- }
-
- /* Pull apart the system and device, and optional user. */
-
- {
- char *cursor;
-
- file_name_copy = xstrdup (file_name);
- remote_host = file_name_copy;
- remote_user = 0;
- remote_file = 0;
-
- for (cursor = file_name_copy; *cursor; cursor++)
- switch (*cursor)
- {
- default:
- break;
-
- case '\n':
- /* Do not allow newlines in the file_name, since the protocol
- uses newline delimiters. */
- free (file_name_copy);
- errno = ENOENT;
- return -1;
-
- case '@':
- if (!remote_user)
- {
- remote_user = remote_host;
- *cursor = '\0';
- remote_host = cursor + 1;
- }
- break;
-
- case ':':
- if (!remote_file)
- {
- *cursor = '\0';
- remote_file = cursor + 1;
- }
- break;
- }
- }
-
- /* FIXME: Should somewhat validate the decoding, here. */
-
- if (remote_user && *remote_user == '\0')
- remote_user = 0;
-
-#if WITH_REXEC
-
- /* Execute the remote command using rexec. */
-
- READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
- if (READ_SIDE (remote_pipe_number) < 0)
- {
- int e = errno;
- free (file_name_copy);
- errno = e;
- return -1;
- }
-
- WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
-
-#else /* not WITH_REXEC */
- {
- const char *remote_shell_basename;
- pid_t status;
-
- /* Identify the remote command to be executed. */
-
- if (!remote_shell)
- {
-#ifdef REMOTE_SHELL
- remote_shell = REMOTE_SHELL;
-#else
- free (file_name_copy);
- errno = EIO;
- return -1;
-#endif
- }
- remote_shell_basename = base_name (remote_shell);
-
- /* Set up the pipes for the `rsh' command, and fork. */
-
- if (pipe (to_remote[remote_pipe_number]) == -1
- || pipe (from_remote[remote_pipe_number]) == -1)
- {
- int e = errno;
- free (file_name_copy);
- errno = e;
- return -1;
- }
-
- status = fork ();
- if (status == -1)
- {
- int e = errno;
- free (file_name_copy);
- errno = e;
- return -1;
- }
-
- if (status == 0)
- {
- /* Child. */
-
- close (STDIN_FILENO);
- dup (to_remote[remote_pipe_number][PREAD]);
- close (to_remote[remote_pipe_number][PREAD]);
- close (to_remote[remote_pipe_number][PWRITE]);
-
- close (STDOUT_FILENO);
- dup (from_remote[remote_pipe_number][PWRITE]);
- close (from_remote[remote_pipe_number][PREAD]);
- close (from_remote[remote_pipe_number][PWRITE]);
-
- sys_reset_uid_gid ();
-
- if (remote_user)
- execl (remote_shell, remote_shell_basename, remote_host,
- "-l", remote_user, rmt_command, (char *) 0);
- else
- execl (remote_shell, remote_shell_basename, remote_host,
- rmt_command, (char *) 0);
-
- /* Bad problems if we get here. */
-
- /* In a previous version, _exit was used here instead of exit. */
- error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell"));
- }
-
- /* Parent. */
-
- close (from_remote[remote_pipe_number][PWRITE]);
- close (to_remote[remote_pipe_number][PREAD]);
- }
-#endif /* not WITH_REXEC */
-
- /* Attempt to open the tape device. */
-
- {
- size_t remote_file_len = strlen (remote_file);
- char *command_buffer = xmalloc (remote_file_len + 1000);
- sprintf (command_buffer, "O%s\n", remote_file);
- encode_oflag (command_buffer + remote_file_len + 2, open_mode);
- strcat (command_buffer, "\n");
- if (do_command (remote_pipe_number, command_buffer) == -1
- || get_status (remote_pipe_number) == -1)
- {
- int e = errno;
- free (command_buffer);
- free (file_name_copy);
- _rmt_shutdown (remote_pipe_number, e);
- return -1;
- }
- free (command_buffer);
- }
-
- free (file_name_copy);
- return remote_pipe_number + bias;
-}
-
-/* Close remote tape connection HANDLE and shut down. Return 0 if
- successful, -1 on error. */
-int
-rmt_close__ (int handle)
-{
- long int status;
-
- if (do_command (handle, "C\n") == -1)
- return -1;
-
- status = get_status (handle);
- _rmt_shutdown (handle, errno);
- return status;
-}
-
-/* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
- Return the number of bytes read on success, SAFE_READ_ERROR on error. */
-size_t
-rmt_read__ (int handle, char *buffer, size_t length)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- size_t status;
- size_t rlen;
- size_t counter;
-
- sprintf (command_buffer, "R%lu\n", (unsigned long) length);
- if (do_command (handle, command_buffer) == -1
- || (status = get_status (handle)) == SAFE_READ_ERROR
- || status > length)
- return SAFE_READ_ERROR;
-
- for (counter = 0; counter < status; counter += rlen, buffer += rlen)
- {
- rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
- if (rlen == SAFE_READ_ERROR || rlen == 0)
- {
- _rmt_shutdown (handle, EIO);
- return SAFE_READ_ERROR;
- }
- }
-
- return status;
-}
-
-/* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
- Return the number of bytes written. */
-size_t
-rmt_write__ (int handle, char *buffer, size_t length)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- RETSIGTYPE (*pipe_handler) ();
- size_t written;
-
- sprintf (command_buffer, "W%lu\n", (unsigned long) length);
- if (do_command (handle, command_buffer) == -1)
- return 0;
-
- pipe_handler = signal (SIGPIPE, SIG_IGN);
- written = full_write (WRITE_SIDE (handle), buffer, length);
- signal (SIGPIPE, pipe_handler);
- if (written == length)
- {
- long int r = get_status (handle);
- if (r < 0)
- return 0;
- if (r == length)
- return length;
- written = r;
- }
-
- /* Write error. */
-
- _rmt_shutdown (handle, EIO);
- return written;
-}
-
-/* Perform an imitation lseek operation on remote tape connection
- HANDLE. Return the new file offset if successful, -1 if on error. */
-off_t
-rmt_lseek__ (int handle, off_t offset, int whence)
-{
- char command_buffer[COMMAND_BUFFER_SIZE];
- char operand_buffer[UINTMAX_STRSIZE_BOUND];
- uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
- char *p = operand_buffer + sizeof operand_buffer;
-
- *--p = 0;
- do
- *--p = '0' + (int) (u % 10);
- while ((u /= 10) != 0);
- if (offset < 0)
- *--p = '-';
-
- switch (whence)
- {
- case SEEK_SET: whence = 0; break;
- case SEEK_CUR: whence = 1; break;
- case SEEK_END: whence = 2; break;
- default: abort ();
- }
-
- sprintf (command_buffer, "L%s\n%d\n", p, whence);
-
- if (do_command (handle, command_buffer) == -1)
- return -1;
-
- return get_status_off (handle);
-}
-
-/* Perform a raw tape operation on remote tape connection HANDLE.
- Return the results of the ioctl, or -1 on error. */
-int
-rmt_ioctl__ (int handle, int operation, char *argument)
-{
- switch (operation)
- {
- default:
- errno = EOPNOTSUPP;
- return -1;
-
-#ifdef MTIOCTOP
- case MTIOCTOP:
- {
- char command_buffer[COMMAND_BUFFER_SIZE];
- char operand_buffer[UINTMAX_STRSIZE_BOUND];
- uintmax_t u = (((struct mtop *) argument)->mt_count < 0
- ? - (uintmax_t) ((struct mtop *) argument)->mt_count
- : (uintmax_t) ((struct mtop *) argument)->mt_count);
- char *p = operand_buffer + sizeof operand_buffer;
-
- *--p = 0;
- do
- *--p = '0' + (int) (u % 10);
- while ((u /= 10) != 0);
- if (((struct mtop *) argument)->mt_count < 0)
- *--p = '-';
-
- /* MTIOCTOP is the easy one. Nothing is transferred in binary. */
-
- sprintf (command_buffer, "I%d\n%s\n",
- ((struct mtop *) argument)->mt_op, p);
- if (do_command (handle, command_buffer) == -1)
- return -1;
-
- return get_status (handle);
- }
-#endif /* MTIOCTOP */
-
-#ifdef MTIOCGET
- case MTIOCGET:
- {
- ssize_t status;
- size_t counter;
-
- /* Grab the status and read it directly into the structure. This
- assumes that the status buffer is not padded and that 2 shorts
- fit in a long without any word alignment problems; i.e., the
- whole struct is contiguous. NOTE - this is probably NOT a good
- assumption. */
-
- if (do_command (handle, "S") == -1
- || (status = get_status (handle), status == -1))
- return -1;
-
- for (; status > 0; status -= counter, argument += counter)
- {
- counter = safe_read (READ_SIDE (handle), argument, status);
- if (counter == SAFE_READ_ERROR || counter == 0)
- {
- _rmt_shutdown (handle, EIO);
- return -1;
- }
- }
-
- /* Check for byte position. mt_type (or mt_model) is a small integer
- field (normally) so we will check its magnitude. If it is larger
- than 256, we will assume that the bytes are swapped and go through
- and reverse all the bytes. */
-
- if (((struct mtget *) argument)->MTIO_CHECK_FIELD < 256)
- return 0;
-
- for (counter = 0; counter < status; counter += 2)
- {
- char copy = argument[counter];
-
- argument[counter] = argument[counter + 1];
- argument[counter + 1] = copy;
- }
-
- return 0;
- }
-#endif /* MTIOCGET */
-
- }
-}
OpenPOWER on IntegriCloud