X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Frtapelib.c;h=c9cd90e6010471966ad2e139478e5a703ff18383;hb=aa985330d59a033156b0d793f880de952eafa4e5;hp=c062eba2bf477b66b7ecf1541c24a8f0969a4df9;hpb=eecb74cb33bb5889b01228c42f734572b7d26094;p=chaz%2Ftar diff --git a/src/rtapelib.c b/src/rtapelib.c index c062eba..c9cd90e 100644 --- a/src/rtapelib.c +++ b/src/rtapelib.c @@ -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 @@ -12,113 +12,114 @@ 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 -#include -#include - -#ifdef HAVE_SYS_MTIO_H -#include -#include + 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 +# endif +# if HAVE_SYS_INET_H +# include +# endif +# ifndef EOPNOTSUPP +# define EOPNOTSUPP EINVAL +# endif #endif -#ifdef HAVE_NETDB_H -#include -#endif - -#include -#include -#include +#include -#ifndef errno -extern int errno; +#if HAVE_NETDB_H +# include #endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef STDC_HEADERS -#include -#include -#endif +#include "rmt.h" -/* Maximum size of a fully qualified host name. */ -#define MAXHOSTLEN 257 +/* FIXME: Just to shut up -Wall. */ +int rexec (); -/* Size of buffers for reading and writing commands to rmt. - (An arbitrary limit.) */ -#define CMDBUFSIZE 64 +/* Exit status if exec errors. */ +#define EXIT_ON_EXEC_ERROR 128 + +/* FIXME: Size of buffers for reading and writing commands to rmt. */ +#define COMMAND_BUFFER_SIZE 64 #ifndef RETSIGTYPE -#define RETSIGTYPE void +# 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__; -/* 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; @@ -127,452 +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/????'. +#endif /* WITH_REXEC */ - OFLAG is O_RDONLY, O_WRONLY, etc. - MODE is ignored; 0666 is always used. +/*------------------------------------------------------------------------. +| 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. | +`------------------------------------------------------------------------*/ - If successful, return the remote tape pipe number plus BIAS. - 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 - while (*path) + /* Execute the remote command using rexec. */ + + 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]; - return i + bias; + 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; + } + } + + 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 (buffer, "L%ld\n%d\n", offset, whence); - if (command (fildes, buffer) == -1) + sprintf (command_buffer, "L%s\n%d\n", p, whence); + + 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 int -__rmt_ioctl (fildes, op, arg) - int fildes, op; - char *arg; +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