]> Dogcows Code - chaz/tar/blobdiff - src/rtapelib.c
Handle EINTR correctly; use STDIN_FILENO instead of 0, etc.
[chaz/tar] / src / rtapelib.c
index c8a41b8b1eafb12c44421924c1c729e7dff1fffc..c9cd90e6010471966ad2e139478e5a703ff18383 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions for communicating with a remote tape drive.
-   Copyright (C) 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1992, 1994, 1996 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
    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., 675 Mass Ave, Cambridge, MA 02139, 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 rmtXXX calls into macros for speed by Jay Fenlason.
-   Use -DHAVE_NETDB_H for rexec code, courtesy of Dan Kegel, srs!dan.  */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <signal.h>
-
-#ifdef HAVE_SYS_MTIO_H
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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"
+
+/* 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
 
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
+#include <signal.h>
+
+#if HAVE_NETDB_H
+# include <netdb.h>
 #endif
 
-#include <errno.h>
-#include <setjmp.h>
-#include <sys/stat.h>
+#include "rmt.h"
 
-#ifndef errno
-extern int errno;
-#endif
+/* FIXME: Just to shut up -Wall.  */
+int rexec ();
 
-/* Maximum size of a fully qualified host name.  */
-#define MAXHOSTLEN 257
+/* Exit status if exec errors.  */
+#define EXIT_ON_EXEC_ERROR 128
 
-/* Size of buffers for reading and writing commands to rmt.
-   (An arbitrary limit.)  */
-#define CMDBUFSIZE 64
+/* FIXME: Size of buffers for reading and writing commands to rmt.  */
+#define COMMAND_BUFFER_SIZE 64
 
 #ifndef RETSIGTYPE
-#define RETSIGTYPE void
+# define RETSIGTYPE void
 #endif
 
-/* Maximum number of simultaneous remote tape connections.
-   (Another arbitrary limit.)  */
+/* FIXME: Maximum number of simultaneous remote tape connections.  */
 #define MAXUNIT        4
 
-/* Return the parent's read side of remote tape connection FILDES.  */
-#define READ(fildes) (from_rmt[fildes][0])
+#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 FILDES.  */
-#define WRITE(fildes) (to_rmt[fildes][1])
+/* 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_rmt[MAXUNIT][2] = {-1, -1, -1, -1, -1, -1, -1, -1};
+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_rmt[MAXUNIT][2] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
 
 /* Temporary variable used by macros in rmt.h.  */
-char *__rmt_path;
+char *rmt_path__;
 \f
-/* Close remote tape connection FILDES.  */
 
-static void 
-_rmt_shutdown (fildes)
-     int fildes;
+/*----------------------------------------------------------------------.
+| Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE.  |
+`----------------------------------------------------------------------*/
+
+static void
+_rmt_shutdown (int handle, int errno_value)
 {
-  close (READ (fildes));
-  close (WRITE (fildes));
-  READ (fildes) = -1;
-  WRITE (fildes) = -1;
+  close (READ_SIDE (handle));
+  close (WRITE_SIDE (handle));
+  READ_SIDE (handle) = -1;
+  WRITE_SIDE (handle) = -1;
+  errno = errno_value;         /* FIXME: errno should be read-only */
 }
 
-/* Attempt to perform the remote tape command specified in BUF
-   on remote tape connection FILDES.
-   Return 0 if successful, -1 on error.  */
+/*-------------------------------------------------------------------------.
+| Attempt to perform the remote tape command specified in BUFFER on remote |
+| tape connection HANDLE.  Return 0 if successful, -1 on error.                   |
+`-------------------------------------------------------------------------*/
 
-static int 
-command (fildes, buf)
-     int fildes;
-     char *buf;
+static int
+do_command (int handle, const char *buffer)
 {
-  register int buflen;
+  size_t length;
   RETSIGTYPE (*pipe_handler) ();
 
   /* Save the current pipe handler and try to make the request.  */
 
   pipe_handler = signal (SIGPIPE, SIG_IGN);
-  buflen = strlen (buf);
-  if (write (WRITE (fildes), buf, buflen) == buflen)
+  length = strlen (buffer);
+  if (full_write (WRITE_SIDE (handle), buffer, length) == length)
     {
       signal (SIGPIPE, pipe_handler);
       return 0;
@@ -119,451 +128,559 @@ command (fildes, buf)
   /* Something went wrong.  Close down and go home.  */
 
   signal (SIGPIPE, pipe_handler);
-  _rmt_shutdown (fildes);
-  errno = EIO;
+  _rmt_shutdown (handle, EIO);
   return -1;
 }
 
-/* Read and return the status from remote tape connection FILDES.
-   If an error occurred, return -1 and set errno.  */
-
-static int 
-status (fildes)
-     int fildes;
+static char *
+get_status_string (int handle, char *command_buffer)
 {
-  int i;
-  char c, *cp;
-  char buffer[CMDBUFSIZE];
+  char *cursor;
+  int counter;
 
   /* Read the reply command line.  */
 
-  for (i = 0, cp = buffer; i < CMDBUFSIZE; i++, cp++)
+  for (counter = 0, cursor = command_buffer;
+       counter < COMMAND_BUFFER_SIZE;
+       counter++, cursor++)
     {
-      if (read (READ (fildes), cp, 1) != 1)
+      if (full_read (READ_SIDE (handle), cursor, 1) != 1)
        {
-         _rmt_shutdown (fildes);
-         errno = EIO;
-         return -1;
+         _rmt_shutdown (handle, EIO);
+         return 0;
        }
-      if (*cp == '\n')
+      if (*cursor == '\n')
        {
-         *cp = '\0';
+         *cursor = '\0';
          break;
        }
     }
 
-  if (i == CMDBUFSIZE)
+  if (counter == COMMAND_BUFFER_SIZE)
     {
-      _rmt_shutdown (fildes);
-      errno = EIO;
-      return -1;
+      _rmt_shutdown (handle, EIO);
+      return 0;
     }
 
   /* Check the return status.  */
 
-  for (cp = buffer; *cp; cp++)
-    if (*cp != ' ')
+  for (cursor = command_buffer; *cursor; cursor++)
+    if (*cursor != ' ')
       break;
 
-  if (*cp == 'E' || *cp == 'F')
+  if (*cursor == 'E' || *cursor == 'F')
     {
-      errno = atoi (cp + 1);
+      errno = atoi (cursor + 1); /* FIXME: errno should be read-only */
+
       /* Skip the error message line.  */
-      while (read (READ (fildes), &c, 1) == 1)
-       if (c == '\n')
-         break;
 
-      if (*cp == 'F')
-       _rmt_shutdown (fildes);
+      /* FIXME: there is better to do than merely ignoring error messages
+        coming from the remote end.  Translate them, too...  */
 
-      return -1;
+      {
+       char character;
+
+       while (full_read (READ_SIDE (handle), &character, 1) == 1)
+         if (character == '\n')
+           break;
+      }
+
+      if (*cursor == 'F')
+       _rmt_shutdown (handle, errno);
+
+      return 0;
     }
 
-  /* Check for mis-synced pipes. */
+  /* Check for mis-synced pipes.  */
 
-  if (*cp != 'A')
+  if (*cursor != 'A')
     {
-      _rmt_shutdown (fildes);
-      errno = EIO;
-      return -1;
+      _rmt_shutdown (handle, EIO);
+      return 0;
     }
 
   /* Got an `A' (success) response.  */
-  return atoi (cp + 1);
+
+  return cursor + 1;
+}
+
+/*----------------------------------------------------------------------.
+| Read and return the status from remote tape connection HANDLE.  If an |
+| error occurred, return -1 and set errno.                             |
+`----------------------------------------------------------------------*/
+
+static long
+get_status (int handle)
+{
+  char command_buffer[COMMAND_BUFFER_SIZE];
+  const char *status = get_status_string (handle, command_buffer);
+  return status ? atol (status) : -1L;
+}
+
+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;
+    }
 }
 
-#ifdef HAVE_NETDB_H
-/* 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 NULL, or an empty string, use the current username.
+#if WITH_REXEC
 
-   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.  */
+/*-------------------------------------------------------------------------.
+| 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 NULL, 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 (host, user)
-     char *host;
-     char *user;
+_rmt_rexec (char *host, char *user)
 {
+  int saved_stdin = dup (STDIN_FILENO);
+  int saved_stdout = dup (STDOUT_FILENO);
   struct servent *rexecserv;
-  int save_stdin = dup (fileno (stdin));
-  int save_stdout = dup (fileno (stdout));
-  int tape_fd;                 /* Return value. */
-
-  /* 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.  */
+  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) == NULL)
     freopen ("/dev/null", "r", stdin);
   if (freopen ("/dev/tty", "w", stdout) == NULL)
     freopen ("/dev/null", "w", stdout);
 
-  rexecserv = getservbyname ("exec", "tcp");
-  if (NULL == rexecserv)
-    {
-      fprintf (stderr, "exec/tcp: service not available");
-      exit (1);
-    }
-  if (user != NULL && *user == '\0')
-    user = NULL;
-  tape_fd = rexec (&host, rexecserv->s_port, user, NULL,
-                  "/etc/rmt", (int *) NULL);
-  fclose (stdin);
-  fdopen (save_stdin, "r");
-  fclose (stdout);
-  fdopen (save_stdout, "w");
+  if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
+    error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
 
-  return tape_fd;
+  result = rexec (&host, rexecserv->s_port, user, NULL,
+                  "/etc/rmt", (int *) NULL);
+  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 /* HAVE_NETDB_H */
-
-/* Open a magtape device on the system specified in PATH, as the given user.
-   PATH has the form `[user@]system:/dev/????'.
-   If COMPAT is defined, it can also have the form `system[.user]:/dev/????'.
 
-   OFLAG is O_RDONLY, O_WRONLY, etc.
-   MODE is ignored; 0666 is always used.
+#endif /* WITH_REXEC */
 
-   If successful, return the remote tape pipe number plus BIAS.
-   On error, return -1.  */
+/*------------------------------------------------------------------------.
+| Open a file (a magnetic tape device?) on the system specified in PATH,  |
+| as the given user.  PATH 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 overriden.  On error, return -1.       |
+`------------------------------------------------------------------------*/
 
-int 
-__rmt_open (path, oflag, mode, bias)
-     char *path;
-     int oflag;
-     int mode;
-     int bias;
+int
+rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
 {
-  int i, rc;
-  char buffer[CMDBUFSIZE];     /* Command buffer.  */
-  char system[MAXHOSTLEN];     /* The remote host name.  */
-  char device[CMDBUFSIZE];     /* The remote device name.  */
-  char login[CMDBUFSIZE];              /* The remote user name.  */
-  char *sys, *dev, *user;      /* For copying into the above buffers.  */
-
-  sys = system;
-  dev = device;
-  user = login;
+  int remote_pipe_number;      /* pseudo, biased file descriptor */
+  char *path_copy ;            /* copy of path 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 (i = 0; i < MAXUNIT; i++)
-    if (READ (i) == -1 && WRITE (i) == -1)
+  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 (i == MAXUNIT)
+  if (remote_pipe_number == MAXUNIT)
     {
-      errno = EMFILE;
+      errno = EMFILE;          /* FIXME: errno should be read-only */
       return -1;
     }
 
-  /* Pull apart the system and device, and optional user.
-     Don't munge the original string.  */
+  /* Pull apart the system and device, and optional user.  */
 
-  while (*path != '@'
-#ifdef COMPAT
-        && *path != '.'
-#endif
-        && *path != ':')
-    {
-      *sys++ = *path++;
-    }
-  *sys = '\0';
-  path++;
+  {
+    char *cursor;
 
-  if (*(path - 1) == '@')
-    {
-      /* Saw user part of user@host.  Start over. */
-      strcpy (user, system);
-      sys = system;
-      while (*path != ':')
-       {
-         *sys++ = *path++;
-       }
-      *sys = '\0';
-      path++;
-    }
-#ifdef COMPAT
-  else if (*(path - 1) == '.')
-    {
-      while (*path != ':')
+    path_copy = xstrdup (path);
+    remote_host = path_copy;
+    remote_user = NULL;
+    remote_file = NULL;
+
+    for (cursor = path_copy; *cursor; cursor++)
+      switch (*cursor)
        {
-         *user++ = *path++;
+       default:
+         break;
+
+       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;
        }
-      *user = '\0';
-      path++;
-    }
-#endif
-  else
-    *user = '\0';
+  }
+
+  /* FIXME: Should somewhat validate the decoding, here.  */
+
+  if (remote_user && *remote_user == '\0')
+    remote_user = NULL;
+
+#if WITH_REXEC
+
+  /* Execute the remote command using rexec.  */
 
-  while (*path)
+  READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
+  if (READ_SIDE (remote_pipe_number) < 0)
     {
-      *dev++ = *path++;
+      free (path_copy);
+      return -1;
     }
-  *dev = '\0';
 
-#ifdef HAVE_NETDB_H
-  /* Execute the remote command using rexec.  */
-  READ (i) = WRITE (i) = _rmt_rexec (system, login);
-  if (READ (i) < 0)
-    return -1;
-#else /* !HAVE_NETDB_H */
-  /* Set up the pipes for the `rsh' command, and fork.  */
+  WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
 
-  if (pipe (to_rmt[i]) == -1 || pipe (from_rmt[i]) == -1)
-    return -1;
+#else /* not WITH_REXEC */
+  {
+    const char *remote_shell_basename;
+    pid_t status;
 
-  rc = fork ();
-  if (rc == -1)
-    return -1;
+    /* Identify the remote command to be executed.  */
 
-  if (rc == 0)
-    {
-      /* Child.  */
-      close (0);
-      dup (to_rmt[i][0]);
-      close (to_rmt[i][0]);
-      close (to_rmt[i][1]);
+    if (!remote_shell)
+      {
+#ifdef REMOTE_SHELL
+       remote_shell = REMOTE_SHELL;
+#else
+       errno = EIO;            /* FIXME: errno should be read-only */
+       free (path_copy);
+       return -1;
+#endif
+      }
+    remote_shell_basename = strrchr (remote_shell, '/');
+    if (remote_shell_basename)
+      remote_shell_basename++;
+    else
+      remote_shell_basename = 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)
+      {
+       free (path_copy);
+       return -1;
+      }
 
-      close (1);
-      dup (from_rmt[i][1]);
-      close (from_rmt[i][0]);
-      close (from_rmt[i][1]);
+    status = fork ();
+    if (status == -1)
+      {
+       free (path_copy);
+       return -1;
+      }
 
-      setuid (getuid ());
-      setgid (getgid ());
+    if (status == 0)
+      {
+       /* Child.  */
 
-      if (*login)
-       {
-         execl ("/usr/ucb/rsh", "rsh", system, "-l", login,
-                "/etc/rmt", (char *) 0);
-         execl ("/usr/bin/remsh", "remsh", system, "-l", login,
-                "/etc/rmt", (char *) 0);
-         execl ("/usr/bin/rsh", "rsh", system, "-l", login,
-                "/etc/rmt", (char *) 0);
-         execl ("/usr/bsd/rsh", "rsh", system, "-l", login,
-                "/etc/rmt", (char *) 0);
-         execl ("/usr/bin/nsh", "nsh", system, "-l", login,
-                "/etc/rmt", (char *) 0);
-       }
-      else
-       {
-         execl ("/usr/ucb/rsh", "rsh", system,
-                "/etc/rmt", (char *) 0);
-         execl ("/usr/bin/remsh", "remsh", system,
-                "/etc/rmt", (char *) 0);
-         execl ("/usr/bin/rsh", "rsh", system,
-                "/etc/rmt", (char *) 0);
-         execl ("/usr/bsd/rsh", "rsh", system,
-                "/etc/rmt", (char *) 0);
-         execl ("/usr/bin/nsh", "nsh", system,
+       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]);
+
+#if !MSDOS
+       setuid (getuid ());
+       setgid (getgid ());
+#endif
+
+       if (remote_user)
+         execl (remote_shell, remote_shell_basename, remote_host,
+                "-l", remote_user, "/etc/rmt", (char *) 0);
+       else
+         execl (remote_shell, remote_shell_basename, remote_host,
                 "/etc/rmt", (char *) 0);
-       }
 
-      /* Bad problems if we get here.  */
+       /* Bad problems if we get here.  */
 
-      perror ("cannot execute remote shell");
-      _exit (1);
-    }
+       /* In a previous version, _exit was used here instead of exit.  */
+       error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell"));
+      }
+
+    /* Parent.  */
 
-  /* Parent.  */
-  close (to_rmt[i][0]);
-  close (from_rmt[i][1]);
-#endif /* !HAVE_NETDB_H */
+    close (from_remote[remote_pipe_number][PWRITE]);
+    close (to_remote[remote_pipe_number][PREAD]);
+  }
+#endif /* not WITH_REXEC */
 
   /* Attempt to open the tape device.  */
 
-  sprintf (buffer, "O%s\n%d\n", device, oflag);
-  if (command (i, buffer) == -1 || status (i) == -1)
-    return -1;
+  {
+    char command_buffer[COMMAND_BUFFER_SIZE];
+
+    sprintf (command_buffer, "O%s\n%d\n", remote_file, open_mode);
+    if (do_command (remote_pipe_number, command_buffer) == -1
+       || get_status (remote_pipe_number) == -1)
+      {
+       _rmt_shutdown (remote_pipe_number, errno);
+       free (path_copy);
+       return -1;
+      }
+  }
 
-  return i + bias;
+  free (path_copy);
+  return remote_pipe_number + bias;
 }
 
-/* Close remote tape connection FILDES and shut down.
-   Return 0 if successful, -1 on error.  */
+/*----------------------------------------------------------------.
+| Close remote tape connection HANDLE and shut down.  Return 0 if |
+| successful, -1 on error.                                       |
+`----------------------------------------------------------------*/
 
-int 
-__rmt_close (fildes)
-     int fildes;
+int
+rmt_close__ (int handle)
 {
-  int rc;
+  int status;
 
-  if (command (fildes, "C\n") == -1)
+  if (do_command (handle, "C\n") == -1)
     return -1;
 
-  rc = status (fildes);
-  _rmt_shutdown (fildes);
-  return rc;
+  status = get_status (handle);
+  _rmt_shutdown (handle, errno);
+  return status;
 }
 
-/* Read up to NBYTE bytes into BUF from remote tape connection FILDES.
-   Return the number of bytes read on success, -1 on error.  */
+/*-------------------------------------------------------------------------.
+| Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.  |
+| Return the number of bytes read on success, -1 on error.                |
+`-------------------------------------------------------------------------*/
 
-int 
-__rmt_read (fildes, buf, nbyte)
-     int fildes;
-     char *buf;
-     unsigned int nbyte;
+ssize_t
+rmt_read__ (int handle, char *buffer, size_t length)
 {
-  int rc, i;
-  char buffer[CMDBUFSIZE];
+  char command_buffer[COMMAND_BUFFER_SIZE];
+  ssize_t status, rlen;
+  size_t counter;
 
-  sprintf (buffer, "R%d\n", nbyte);
-  if (command (fildes, buffer) == -1 || (rc = status (fildes)) == -1)
+  sprintf (command_buffer, "R%lu\n", (unsigned long) length);
+  if (do_command (handle, command_buffer) == -1
+      || (status = get_status (handle)) == -1)
     return -1;
 
-  for (i = 0; i < rc; i += nbyte, buf += nbyte)
+  for (counter = 0; counter < status; counter += rlen, buffer += rlen)
     {
-      nbyte = read (READ (fildes), buf, rc);
-      if (nbyte <= 0)
+      rlen = full_read (READ_SIDE (handle), buffer, status - counter);
+      if (rlen <= 0)
        {
-         _rmt_shutdown (fildes);
-         errno = EIO;
+         _rmt_shutdown (handle, EIO);
          return -1;
        }
     }
 
-  return rc;
+  return status;
 }
 
-/* Write NBYTE bytes from BUF to remote tape connection FILDES.
-   Return the number of bytes written on success, -1 on error.  */
+/*-------------------------------------------------------------------------.
+| Write LENGTH bytes from BUFFER to remote tape connection HANDLE.  Return |
+| the number of bytes written on success, -1 on error.                    |
+`-------------------------------------------------------------------------*/
 
-int 
-__rmt_write (fildes, buf, nbyte)
-     int fildes;
-     char *buf;
-     unsigned int nbyte;
+ssize_t
+rmt_write__ (int handle, char *buffer, size_t length)
 {
-  char buffer[CMDBUFSIZE];
+  char command_buffer[COMMAND_BUFFER_SIZE];
   RETSIGTYPE (*pipe_handler) ();
 
-  sprintf (buffer, "W%d\n", nbyte);
-  if (command (fildes, buffer) == -1)
+  sprintf (command_buffer, "W%lu\n", (unsigned long) length);
+  if (do_command (handle, command_buffer) == -1)
     return -1;
 
   pipe_handler = signal (SIGPIPE, SIG_IGN);
-  if (write (WRITE (fildes), buf, nbyte) == nbyte)
+  if (full_write (WRITE_SIDE (handle), buffer, length) == length)
     {
       signal (SIGPIPE, pipe_handler);
-      return status (fildes);
+      return get_status (handle);
     }
 
   /* Write error.  */
+
   signal (SIGPIPE, pipe_handler);
-  _rmt_shutdown (fildes);
-  errno = EIO;
+  _rmt_shutdown (handle, EIO);
   return -1;
 }
 
-/* Perform an imitation lseek operation on remote tape connection FILDES.
-   Return the new file offset if successful, -1 if on error.  */
+/*------------------------------------------------------------------------.
+| Perform an imitation lseek operation on remote tape connection HANDLE.  |
+| Return the new file offset if successful, -1 if on error.              |
+`------------------------------------------------------------------------*/
 
-long 
-__rmt_lseek (fildes, offset, whence)
-     int fildes;
-     long offset;
-     int whence;
+off_t
+rmt_lseek__ (int handle, off_t offset, int whence)
 {
-  char buffer[CMDBUFSIZE];
+  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;
+
+  do
+    *--p = '0' + (int) (u % 10);
+  while ((u /= 10) != 0);
+  if (offset < 0)
+    *--p = '-';
+
+  sprintf (command_buffer, "L%s\n%d\n", p, whence);
 
-  sprintf (buffer, "L%ld\n%d\n", offset, whence);
-  if (command (fildes, buffer) == -1)
+  if (do_command (handle, command_buffer) == -1)
     return -1;
 
-  return status (fildes);
+  return get_status_off (handle);
 }
 
-/* Perform a raw tape operation on remote tape connection FILDES.
-   Return the results of the ioctl, or -1 on error.  */
+/*-----------------------------------------------------------------------.
+| Perform a raw tape operation on remote tape connection HANDLE.  Return |
+| the results of the ioctl, or -1 on error.                             |
+`-----------------------------------------------------------------------*/
 
-#ifdef MTIOCTOP
-__rmt_ioctl (fildes, op, arg)
-     int fildes, op;
-     char *arg;
+int
+rmt_ioctl__ (int handle, int operation, char *argument)
 {
-  char c;
-  int rc, cnt;
-  char buffer[CMDBUFSIZE];
-
-  switch (op)
+  switch (operation)
     {
     default:
-      errno = EINVAL;
+      errno = EOPNOTSUPP;      /* FIXME: errno should be read-only */
       return -1;
 
+#ifdef MTIOCTOP
     case MTIOCTOP:
-      /* MTIOCTOP is the easy one.  Nothing is transfered in binary.  */
-      sprintf (buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
-              ((struct mtop *) arg)->mt_count);
-      if (command (fildes, buffer) == -1)
-       return -1;
-      return status (fildes);  /* Return the count.  */
-
-    case MTIOCGET:
-      /* 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.  */
+      {
+       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;
+       
+       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 transfered 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;
 
-      if (command (fildes, "S") == -1 || (rc = status (fildes)) == -1)
-       return -1;
+       return get_status (handle);
+      }
+#endif /* MTIOCTOP */
 
-      for (; rc > 0; rc -= cnt, arg += cnt)
-       {
-         cnt = read (READ (fildes), arg, rc);
-         if (cnt <= 0)
-           {
-             _rmt_shutdown (fildes);
-             errno = EIO;
-             return -1;
-           }
-       }
+#ifdef MTIOCGET
+    case MTIOCGET:
+      {
+       ssize_t status;
+       ssize_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;
 
-      /* Check for byte position.  mt_type 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.  */
+       for (; status > 0; status -= counter, argument += counter)
+         {
+           counter = full_read (READ_SIDE (handle),
+                                argument, (size_t) status);
+           if (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;
+         }
 
-      if (((struct mtget *) arg)->mt_type < 256)
        return 0;
+      }
+#endif /* MTIOCGET */
 
-      for (cnt = 0; cnt < rc; cnt += 2)
-       {
-         c = arg[cnt];
-         arg[cnt] = arg[cnt + 1];
-         arg[cnt + 1] = c;
-       }
-
-      return 0;
     }
 }
-#endif
This page took 0.047007 seconds and 4 git commands to generate.