]> Dogcows Code - chaz/tar/blobdiff - src/rtapelib.c
(decode_oflag): O_APPEND might not be defined.
[chaz/tar] / src / rtapelib.c
index d02386b51e896b368aee0d7682f6f013dab09eec..19d2d2dd7d885f221ccae788be6f0230b1637685 100644 (file)
@@ -1,5 +1,5 @@
 /* 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 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
@@ -32,6 +32,9 @@
 
 #include "system.h"
 
+#include "basename.h"
+#include "safe-read.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.  */
 
@@ -101,7 +104,7 @@ _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;
 }
 
 /*-------------------------------------------------------------------------.
@@ -119,7 +122,7 @@ do_command (int handle, const char *buffer)
 
   pipe_handler = signal (SIGPIPE, SIG_IGN);
   length = strlen (buffer);
-  if (write (WRITE_SIDE (handle), buffer, length) == length)
+  if (full_write (WRITE_SIDE (handle), buffer, length) == length)
     {
       signal (SIGPIPE, pipe_handler);
       return 0;
@@ -144,7 +147,7 @@ get_status_string (int handle, char *command_buffer)
        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 0;
@@ -170,7 +173,7 @@ get_status_string (int handle, char *command_buffer)
 
   if (*cursor == 'E' || *cursor == 'F')
     {
-      errno = atoi (cursor + 1); /* FIXME: errno should be read-only */
+      errno = atoi (cursor + 1);
 
       /* Skip the error message line.  */
 
@@ -180,7 +183,7 @@ get_status_string (int handle, char *command_buffer)
       {
        char character;
 
-       while (read (READ_SIDE (handle), &character, 1) == 1)
+       while (safe_read (READ_SIDE (handle), &character, 1) == 1)
          if (character == '\n')
            break;
       }
@@ -264,7 +267,7 @@ get_status_off (int handle)
 /*-------------------------------------------------------------------------.
 | 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.                                 |
+| 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        |
@@ -276,8 +279,8 @@ get_status_off (int handle)
 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;
 
@@ -287,16 +290,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, "/etc/rmt", 0);
   if (fclose (stdin) == EOF)
     error (0, errno, _("stdin"));
   fdopen (saved_stdin, "r");
@@ -309,11 +311,54 @@ _rmt_rexec (char *host, char *user)
 
 #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
+#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 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.       |
+| plus BIAS.  REMOTE_SHELL may be overridden.  On error, return -1.      |
 `------------------------------------------------------------------------*/
 
 int
@@ -336,7 +381,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;
     }
 
@@ -347,8 +392,8 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
 
     path_copy = xstrdup (path);
     remote_host = path_copy;
-    remote_user = NULL;
-    remote_file = NULL;
+    remote_user = 0;
+    remote_file = 0;
 
     for (cursor = path_copy; *cursor; cursor++)
       switch (*cursor)
@@ -356,6 +401,13 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
        default:
          break;
 
+       case '\n':
+         /* Do not allow newlines in the path, since the protocol
+            uses newline delimiters.  */
+         free (path_copy);
+         errno = ENOENT;
+         return -1;
+
        case '@':
          if (!remote_user)
            {
@@ -378,7 +430,7 @@ 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 WITH_REXEC
 
@@ -387,7 +439,9 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
   READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
   if (READ_SIDE (remote_pipe_number) < 0)
     {
+      int e = errno;
       free (path_copy);
+      errno = e;
       return -1;
     }
 
@@ -405,30 +459,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);
+       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)
       {
+       int e = errno;
        free (path_copy);
+       errno = e;
        return -1;
       }
 
     status = fork ();
     if (status == -1)
       {
+       int e = errno;
        free (path_copy);
+       errno = e;
        return -1;
       }
 
@@ -436,12 +490,12 @@ 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]);
@@ -474,16 +528,21 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
   /* 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);
+       int e = errno;
+       free (command_buffer);
        free (path_copy);
+       _rmt_shutdown (remote_pipe_number, e);
        return -1;
       }
+    free (command_buffer);
   }
 
   free (path_copy);
@@ -527,7 +586,7 @@ rmt_read__ (int handle, char *buffer, size_t length)
 
   for (counter = 0; counter < status; counter += rlen, buffer += rlen)
     {
-      rlen = read (READ_SIDE (handle), buffer, status - counter);
+      rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
       if (rlen <= 0)
        {
          _rmt_shutdown (handle, EIO);
@@ -554,7 +613,7 @@ rmt_write__ (int handle, char *buffer, size_t length)
     return -1;
 
   pipe_handler = signal (SIGPIPE, SIG_IGN);
-  if (write (WRITE_SIDE (handle), buffer, length) == length)
+  if (full_write (WRITE_SIDE (handle), buffer, length) == length)
     {
       signal (SIGPIPE, pipe_handler);
       return get_status (handle);
@@ -586,6 +645,14 @@ rmt_lseek__ (int handle, off_t offset, int whence)
   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)
@@ -605,7 +672,7 @@ 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
@@ -624,7 +691,7 @@ rmt_ioctl__ (int handle, int operation, char *argument)
        if (((struct mtop *) argument)->mt_count < 0)
          *--p = '-';
 
-       /* MTIOCTOP is the easy one.  Nothing is transfered in binary.  */
+       /* MTIOCTOP is the easy one.  Nothing is transferred in binary.  */
 
        sprintf (command_buffer, "I%d\n%s\n",
                 ((struct mtop *) argument)->mt_op, p);
@@ -653,7 +720,7 @@ rmt_ioctl__ (int handle, int operation, char *argument)
 
        for (; status > 0; status -= counter, argument += counter)
          {
-           counter = read (READ_SIDE (handle), argument, (size_t) status);
+           counter = safe_read (READ_SIDE (handle), argument, status);
            if (counter <= 0)
              {
                _rmt_shutdown (handle, EIO);
This page took 0.028794 seconds and 4 git commands to generate.