]> Dogcows Code - chaz/tar/blobdiff - src/rtapelib.c
Updated
[chaz/tar] / src / rtapelib.c
index 7361bb245cb5217c9f5bae8260d961142835e2ef..a31a8930c912cffca617ac4e9f9e2c294983c70a 100644 (file)
@@ -1,5 +1,7 @@
 /* Functions for communicating with a remote tape drive.
-   Copyright (C) 1988, 1992, 1994, 1996 Free Software Foundation, Inc.
+
+   Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2004 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
    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 -DHAVE_NETDB_H for rexec
+   into macros for speed by Jay Fenlason.  Use -DWITH_REXEC for rexec
    code, courtesy of Dan Kegel.  */
 
 #include "system.h"
+#include "common.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.  */
@@ -55,9 +60,6 @@
 
 #include "rmt.h"
 
-/* FIXME: Just to shut up -Wall.  */
-int rexec ();
-
 /* Exit status if exec errors.  */
 #define EXIT_ON_EXEC_ERROR 128
 
@@ -86,14 +88,13 @@ 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}};
 
+#define RMT_COMMAND (rmt_command_option ? rmt_command_option : "/etc/rmt")
+
 /* Temporary variable used by macros in rmt.h.  */
-char *rmt_path__;
+char *rmt_dev_name__;
 \f
 
-/*----------------------------------------------------------------------.
-| Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE.  |
-`----------------------------------------------------------------------*/
-
+/* Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE.  */
 static void
 _rmt_shutdown (int handle, int errno_value)
 {
@@ -101,46 +102,34 @@ _rmt_shutdown (int handle, int errno_value)
   close (WRITE_SIDE (handle));
   READ_SIDE (handle) = -1;
   WRITE_SIDE (handle) = -1;
-  errno = errno_value;         /* FIXME: errno should be read-only */
+  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.                   |
-`-------------------------------------------------------------------------*/
-
+/* 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)
 {
-  int length;
-  RETSIGTYPE (*pipe_handler) ();
-
   /* Save the current pipe handler and try to make the request.  */
 
-  pipe_handler = signal (SIGPIPE, SIG_IGN);
-  length = strlen (buffer);
-  if (write (WRITE_SIDE (handle), buffer, (size_t) length) == length)
-    {
-      signal (SIGPIPE, pipe_handler);
-      return 0;
-    }
+  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.  */
 
-  signal (SIGPIPE, pipe_handler);
   _rmt_shutdown (handle, EIO);
   return -1;
 }
 
-/*----------------------------------------------------------------------.
-| Read and return the status from remote tape connection HANDLE.  If an |
-| error occurred, return -1 and set errno.                             |
-`----------------------------------------------------------------------*/
-
-static int
-get_status (int handle)
+static char *
+get_status_string (int handle, char *command_buffer)
 {
-  char command_buffer[COMMAND_BUFFER_SIZE];
   char *cursor;
   int counter;
 
@@ -150,10 +139,10 @@ get_status (int handle)
        counter < COMMAND_BUFFER_SIZE;
        counter++, cursor++)
     {
-      if (read (READ_SIDE (handle), cursor, 1) != 1)
+      if (safe_read (READ_SIDE (handle), cursor, 1) != 1)
        {
          _rmt_shutdown (handle, EIO);
-         return -1;
+         return 0;
        }
       if (*cursor == '\n')
        {
@@ -165,7 +154,7 @@ get_status (int handle)
   if (counter == COMMAND_BUFFER_SIZE)
     {
       _rmt_shutdown (handle, EIO);
-      return -1;
+      return 0;
     }
 
   /* Check the return status.  */
@@ -176,8 +165,6 @@ get_status (int handle)
 
   if (*cursor == 'E' || *cursor == 'F')
     {
-      errno = atoi (cursor + 1); /* FIXME: errno should be read-only */
-
       /* Skip the error message line.  */
 
       /* FIXME: there is better to do than merely ignoring error messages
@@ -186,15 +173,17 @@ get_status (int handle)
       {
        char character;
 
-       while (read (READ_SIDE (handle), &character, 1) == 1)
+       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 -1;
+      return 0;
     }
 
   /* Check for mis-synced pipes.  */
@@ -202,33 +191,89 @@ get_status (int handle)
   if (*cursor != 'A')
     {
       _rmt_shutdown (handle, EIO);
-      return -1;
+      return 0;
     }
 
   /* Got an `A' (success) response.  */
 
-  return atoi (cursor + 1);
+  return cursor + 1;
 }
 
-#if HAVE_NETDB_H
+/* 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 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.                                             |
-`-------------------------------------------------------------------------*/
+/* 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 (fileno (stdin));
-  int saved_stdout = dup (fileno (stdout));
+  int saved_stdin = dup (STDIN_FILENO);
+  int saved_stdout = dup (STDOUT_FILENO);
   struct servent *rexecserv;
   int result;
 
@@ -238,16 +283,15 @@ _rmt_rexec (char *host, char *user)
      /dev/tty before the rexec and give them back their original value
      after.  */
 
-  if (freopen ("/dev/tty", "r", stdin) == NULL)
+  if (! freopen ("/dev/tty", "r", stdin))
     freopen ("/dev/null", "r", stdin);
-  if (freopen ("/dev/tty", "w", stdout) == NULL)
+  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, NULL,
-                  "/etc/rmt", (int *) NULL);
+  result = rexec (&host, rexecserv->s_port, user, 0, RMT_COMMAND, 0);
   if (fclose (stdin) == EOF)
     error (0, errno, _("stdin"));
   fdopen (saved_stdin, "r");
@@ -258,20 +302,62 @@ _rmt_rexec (char *host, char *user)
   return result;
 }
 
-#endif /* HAVE_NETDB_H */
+#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 ();
+    }
 
-/*------------------------------------------------------------------------.
-| 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.       |
-`------------------------------------------------------------------------*/
+#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
+#ifdef O_NONBLOCK
+  if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK");
+#endif
+#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 *path, int open_mode, int bias, const char *remote_shell)
+rmt_open__ (const char *file_name, int open_mode, int bias, 
+            const char *remote_shell)
 {
   int remote_pipe_number;      /* pseudo, biased file descriptor */
-  char *path_copy ;            /* copy of path string */
+  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 */
@@ -287,7 +373,7 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
 
   if (remote_pipe_number == MAXUNIT)
     {
-      errno = EMFILE;          /* FIXME: errno should be read-only */
+      errno = EMFILE;
       return -1;
     }
 
@@ -296,17 +382,24 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
   {
     char *cursor;
 
-    path_copy = xstrdup (path);
-    remote_host = path_copy;
-    remote_user = NULL;
-    remote_file = NULL;
+    file_name_copy = xstrdup (file_name);
+    remote_host = file_name_copy;
+    remote_user = 0;
+    remote_file = 0;
 
-    for (cursor = path_copy; *cursor; cursor++)
+    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)
            {
@@ -329,25 +422,27 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
   /* FIXME: Should somewhat validate the decoding, here.  */
 
   if (remote_user && *remote_user == '\0')
-    remote_user = NULL;
+    remote_user = 0;
 
-#if HAVE_NETDB_H
+#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)
     {
-      free (path_copy);
+      int e = errno;
+      free (file_name_copy);
+      errno = e;
       return -1;
     }
 
   WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
 
-#else /* not HAVE_NETDB_H */
+#else /* not WITH_REXEC */
   {
     const char *remote_shell_basename;
-    int status;
+    pid_t status;
 
     /* Identify the remote command to be executed.  */
 
@@ -356,30 +451,30 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
 #ifdef REMOTE_SHELL
        remote_shell = REMOTE_SHELL;
 #else
-       errno = EIO;            /* FIXME: errno should be read-only */
-       free (path_copy);
+       free (file_name_copy);
+       errno = EIO;
        return -1;
 #endif
       }
-    remote_shell_basename = strrchr (remote_shell, '/');
-    if (remote_shell_basename)
-      remote_shell_basename++;
-    else
-      remote_shell_basename = remote_shell;
+    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)
       {
-       free (path_copy);
+       int e = errno;
+       free (file_name_copy);
+       errno = e;
        return -1;
       }
 
     status = fork ();
     if (status == -1)
       {
-       free (path_copy);
+       int e = errno;
+       free (file_name_copy);
+       errno = e;
        return -1;
       }
 
@@ -387,27 +482,24 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
       {
        /* Child.  */
 
-       close (0);
+       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 (1);
+       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
+       sys_reset_uid_gid ();
 
        if (remote_user)
          execl (remote_shell, remote_shell_basename, remote_host,
-                "-l", remote_user, "/etc/rmt", (char *) 0);
+                "-l", remote_user, RMT_COMMAND, (char *) 0);
        else
          execl (remote_shell, remote_shell_basename, remote_host,
-                "/etc/rmt", (char *) 0);
+                RMT_COMMAND, (char *) 0);
 
        /* Bad problems if we get here.  */
 
@@ -420,36 +512,38 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
     close (from_remote[remote_pipe_number][PWRITE]);
     close (to_remote[remote_pipe_number][PREAD]);
   }
-#endif /* not HAVE_NETDB_H */
+#endif /* not WITH_REXEC */
 
   /* Attempt to open the tape device.  */
 
   {
-    char command_buffer[COMMAND_BUFFER_SIZE];
-
-    sprintf (command_buffer, "O%s\n%d\n", remote_file, open_mode);
+    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)
       {
-       _rmt_shutdown (remote_pipe_number, errno);
-       free (path_copy);
+       int e = errno;
+       free (command_buffer);
+       free (file_name_copy);
+       _rmt_shutdown (remote_pipe_number, e);
        return -1;
       }
+    free (command_buffer);
   }
 
-  free (path_copy);
+  free (file_name_copy);
   return remote_pipe_number + bias;
 }
 
-/*----------------------------------------------------------------.
-| Close remote tape connection HANDLE 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__ (int handle)
 {
-  int status;
+  long int status;
 
   if (do_command (handle, "C\n") == -1)
     return -1;
@@ -459,110 +553,134 @@ rmt_close__ (int handle)
   return status;
 }
 
-/*-------------------------------------------------------------------------.
-| 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__ (int handle, char *buffer, unsigned int length)
+/* 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];
-  int status;
-  int counter;
+  size_t status;
+  size_t rlen;
+  size_t counter;
 
-  sprintf (command_buffer, "R%d\n", length);
+  sprintf (command_buffer, "R%lu\n", (unsigned long) length);
   if (do_command (handle, command_buffer) == -1
-      || (status = get_status (handle)) == -1)
-    return -1;
+      || (status = get_status (handle)) == SAFE_READ_ERROR)
+    return SAFE_READ_ERROR;
 
-  for (counter = 0; counter < status; counter += length, buffer += length)
+  for (counter = 0; counter < status; counter += rlen, buffer += rlen)
     {
-      length = read (READ_SIDE (handle), buffer, (size_t) (status - counter));
-      if (length <= 0)
+      rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
+      if (rlen == SAFE_READ_ERROR || rlen == 0)
        {
          _rmt_shutdown (handle, EIO);
-         return -1;
+         return SAFE_READ_ERROR;
        }
     }
 
   return status;
 }
 
-/*-------------------------------------------------------------------------.
-| Write LENGTH bytes from BUFFER to remote tape connection HANDLE.  Return |
-| the number of bytes written on success, -1 on error.                    |
-`-------------------------------------------------------------------------*/
-
-int
-rmt_write__ (int handle, char *buffer, unsigned int length)
+/* 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%d\n", length);
+  sprintf (command_buffer, "W%lu\n", (unsigned long) length);
   if (do_command (handle, command_buffer) == -1)
-    return -1;
+    return 0;
 
   pipe_handler = signal (SIGPIPE, SIG_IGN);
-  if (write (WRITE_SIDE (handle), buffer, length) == length)
+  written = full_write (WRITE_SIDE (handle), buffer, length);
+  signal (SIGPIPE, pipe_handler);
+  if (written == length)
     {
-      signal (SIGPIPE, pipe_handler);
-      return get_status (handle);
+      long int r = get_status (handle);
+      if (r < 0)
+       return 0;
+      if (r == length)
+       return length;
+      written = r;
     }
 
   /* Write error.  */
 
-  signal (SIGPIPE, pipe_handler);
   _rmt_shutdown (handle, EIO);
-  return -1;
+  return written;
 }
 
-/*------------------------------------------------------------------------.
-| Perform an imitation lseek operation on remote tape connection HANDLE.  |
-| Return the new file offset if successful, -1 if on error.              |
-`------------------------------------------------------------------------*/
-
-long
+/* 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);
 
-  sprintf (command_buffer, "L%ld\n%d\n", offset, whence);
   if (do_command (handle, command_buffer) == -1)
     return -1;
 
-  return get_status (handle);
+  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.                             |
-`-----------------------------------------------------------------------*/
-
+/* 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;      /* FIXME: errno should be read-only */
+      errno = EOPNOTSUPP;
       return -1;
 
 #ifdef MTIOCTOP
     case MTIOCTOP:
       {
        char command_buffer[COMMAND_BUFFER_SIZE];
-
-       /* MTIOCTOP is the easy one.  Nothing is transfered in binary.  */
-
-       sprintf (command_buffer, "I%d\n%d\n", ((struct mtop *) argument)->mt_op,
-                ((struct mtop *) argument)->mt_count);
+       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 the count.  */
-
        return get_status (handle);
       }
 #endif /* MTIOCTOP */
@@ -570,8 +688,8 @@ rmt_ioctl__ (int handle, int operation, char *argument)
 #ifdef MTIOCGET
     case MTIOCGET:
       {
-       int status;
-       int counter;
+       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
@@ -585,8 +703,8 @@ rmt_ioctl__ (int handle, int operation, char *argument)
 
        for (; status > 0; status -= counter, argument += counter)
          {
-           counter = read (READ_SIDE (handle), argument, (size_t) status);
-           if (counter <= 0)
+           counter = safe_read (READ_SIDE (handle), argument, status);
+           if (counter == SAFE_READ_ERROR || counter == 0)
              {
                _rmt_shutdown (handle, EIO);
                return -1;
This page took 0.040266 seconds and 4 git commands to generate.