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