--- Makefile.in +++ Makefile.in 2000/12/03 14:36:49 @@ -103,12 +103,12 @@ rtapelib.c dirname.c idcache.c makepath.c xmalloc.c stripslash.c \ userspec.c xstrdup.c bcopy.c fnmatch.c mkdir.c strdup.c OBJS = copyin.o copyout.o copypass.o defer.o dstring.o global.o \ -main.o tar.o util.o error.o getopt.o getopt1.o filemode.o version.o \ +main.o tar.o util.o error.o filemode.o version.o \ $(RTAPELIB) dirname.o idcache.o makepath.o xmalloc.o stripslash.o \ userspec.o xstrdup.o @LIBOBJS@ @FNMATCH@ @ALLOCA@ # mt source files not shared with cpio. MT_SRCS = mt.c argmatch.c -MT_OBJS = mt.o argmatch.o error.o getopt.o getopt1.o \ +MT_OBJS = mt.o argmatch.o error.o \ xmalloc.o version.o $(RTAPELIB) @ALLOCA@ HDRS = cpio.h cpiohdr.h tar.h tarhdr.h defer.h dstring.h extern.h filetypes.h \ system.h fnmatch.h getopt.h rmt.h safe-stat.h --- configure +++ configure 2000/12/03 14:41:28 @@ -1035,7 +1035,7 @@ ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* - PROGS="$PROGS rmt" + PROGS="$PROGS" else echo "$ac_err" >&5 fi @@ -1456,7 +1456,7 @@ FNMATCH="fnmatch.o" fi -for ac_func in strerror lchown +for ac_func in strerror lchown endpwent endgrent do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then --- configure.in +++ configure.in 2000/12/03 14:41:43 @@ -17,7 +17,7 @@ [AC_DEFINE(HAVE_SYS_MTIO_H) PROGS="$PROGS mt" AC_TRY_CPP([#include -#include ], PROGS="$PROGS rmt")]) +#include ], PROGS="$PROGS")]) AC_CHECKING(for remote shell) if test -f /usr/ucb/rsh || test -f /usr/bin/remsh || test -f /usr/bin/rsh || @@ -58,7 +58,7 @@ FNMATCH="fnmatch.o" fi AC_SUBST(FNMATCH) -AC_CHECK_FUNCS(strerror lchown) +AC_CHECK_FUNCS(strerror lchown endpwent endgrent) AC_FUNC_VPRINTF AC_FUNC_ALLOCA AC_HEADER_DIRENT --- copyin.c +++ copyin.c 2000/12/03 14:40:00 @@ -389,6 +389,7 @@ int cdf_flag; /* True if file is a CDF. */ int cdf_char; /* Index of `+' char indicating a CDF. */ #endif + int lastpattern = 0; /* Initialize the copy in. */ if (pattern_file_name) @@ -512,8 +519,10 @@ for (i = 0; i < num_patterns && skip_file == copy_matching_files; i++) { - if (fnmatch (save_patterns[i], file_hdr.c_name, 0) == 0) + if (fnmatch (save_patterns[lastpattern], file_hdr.c_name, 0) == 0) skip_file = !copy_matching_files; + else if (++lastpattern >= num_patterns) + lastpattern = 0; } } --- copyout.c +++ copyout.c 2000/12/03 14:36:49 @@ -108,7 +108,7 @@ int dev = 0, rdev = 0; #endif - if ((file_hdr->c_ino >> 16) != 0) + if ((file_hdr->c_ino >> 16) != 0 && !(file_hdr->c_mode & CP_IFLNK)) error (0, 0, "%s: truncating inode number", file_hdr->c_name); sprintf (ascii_header, @@ -135,7 +135,7 @@ short_hdr.c_magic = 070707; short_hdr.c_dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min); - if ((file_hdr->c_ino >> 16) != 0) + if ((file_hdr->c_ino >> 16) != 0 && !(file_hdr->c_mode & CP_IFLNK)) error (0, 0, "%s: truncating inode number", file_hdr->c_name); short_hdr.c_ino = file_hdr->c_ino & 0xFFFF; --- mt.1 +++ mt.1 2000/12/03 14:36:49 @@ -76,9 +76,6 @@ .IR count . Equivalent to rewind followed by fsf .IR count . -.IP seek -Seek to block number -.IR count . .IP eom Space to the end of the recorded media on the tape (for appending files onto tapes). @@ -93,6 +90,69 @@ then rewind it again. .IP erase Erase the tape. +.IP fss +(SCSI tapes) Forward space +.I count +setmarks. +.IP bss +(SCSI tapes) Backward space +.I count +setmarks. +.IP "wset" +(SCSI tapes) Write +.I count +setmarks at current position (only SCSI tape). +.IP "eod, seod" +Space to end of valid data. Used on streamer tape +drives to append data to the logical and of tape. +.IP setblk +(SCSI tapes) Set the block size of the drive to +.I count +bytes per record. +.IP setdensity +(SCSI tapes) Set the tape density code to +.I count. +The proper codes to use with each drive should be looked up from the +drive documentation. +.IP drvbuffer +(SCSI tapes) Set the tape drive buffer code to +.I number. +The proper value for unbuffered operation is zero and "normal" buffered +operation one. The meanings of other values can be found in the drive +documentation or, in case of a SCSI-2 drive, from the SCSI-2 standard. +.IP stoptions +(SCSI tapes) Set the driver options bits to +.I count +for the device. +The bits can be set by oring the following values: 1 to enable write +buffering, 2 to enable asynchronous writes, 4 to enable read ahead, +8 to enable debugging output (if it has been compiled to the driver). +.IP stwrthreshold +(SCSI tapes) The write threshold for the tape device is set to +.I count +kilobytes. The value must be smaller than or equal to the driver +buffer size. +.IP seek +(SCSI tapes) Seek to the +.I count +block on the tape. This operation is available on some +Tandberg and Wangtek streamers and some SCSI-2 tape drives. +.IP tell +(SCSI tapes) Tell the current block on tape. This operation is available on some +Tandberg and Wangtek streamers and some SCSI-2 tape drives. +.IP densities +(SCSI tapes) Write explanation of some common density codes to +standard output. +.IP datcompression +(some SCSI-2 DAT tapes) Inquire or set the compression status +(on/off). If the +.I count +is one the compression status is printed. If the +.I count +is zero, compression is disabled. Otherwise, compression is +enabled. The command uses the SCSI ioctl to read and write the Data +Compression Characteristics mode page (15). ONLY ROOT CAN USE THIS +COMMAND. .PP .B mt exits with a status of 0 if the operation succeeded, 1 if the --- mt.c +++ mt.c 2002/07/05 09:12:48 @@ -16,6 +16,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +/* Modified for the Linux SCSI tape driver by Brian Mays from code + written by Kai Makisara. + Last Modified: Tue Apr 23 15:37:54 EDT 1996 +*/ /* If -f is not given, the environment variable TAPE is used; if that is not set, a default device defined in sys/mtio.h is used. @@ -50,6 +54,46 @@ retension Rewind the tape, then wind it to the end of the reel, then rewind it again. erase Erase the tape. + fss (SCSI tapes) Forward space COUNT setmarks. + bss (SCSI tapes) Backward space COUNT setmarks. + wset (SCSI tapes) Write COUNT setmarks at current position + (only SCSI tape). + eod, seod Space to end of valid data. Used on streamer tape + drives to append data to the logical and of tape. + setblk (SCSI tapes) Set the block size of the drive to COUNT + bytes per record. + setdensity (SCSI tapes) Set the tape density code to COUNT. The + proper codes to use with each drive should be looked + up from the drive documentation. + drvbuffer (SCSI tapes) Set the tape drive buffer code to + NUMBER. The proper value for unbuffered operation is + zero and "normal" buffered operation one. The meanings + of other values can be found in the drive + documentation or, in case of a SCSI-2 drive, from the + SCSI-2 standard. + stoptions (SCSI tapes) Set the driver options bits to COUNT for + the device. The bits can be set by oring the + following values: 1 to enable write buffering, 2 to + enable asynchronous writes, 4 to enable read ahead, 8 + to enable debugging output (if it has been compiled to + the driver). + stwrthreshold + (SCSI tapes) The write threshold for the tape device + is set to COUNT kilobytes. The value must be smaller + than or equal to the driver buffer size. + seek (SCSI tapes) Seek to the COUNT block on the tape. + This operation is available on some Tandberg and + Wangtek streamers and some SCSI-2 tape drives. + tell (SCSI tapes) Tell the current block on tape. This + operation is available on some Tandberg and Wangtek + streamers and some SCSI-2 tape drives. + densities (SCSI tapes) Write explanation of some common density + codes to standard output. + datcompression + (some SCSI-2 DAT tapes) Inquire or set the compression + status (on/off). If the COUNT is one the compression + status is printed. If the COUNT is zero, compression + is disabled. Otherwise, compression is enabled. David MacKenzie */ @@ -97,6 +141,45 @@ void perform_operation (); void print_status (); void usage (); +#ifdef MTTELL +void print_position (); +#endif + +#if defined(linux) || defined(__linux) +#define MTDATCOMP 1000 /* Random unused number. */ +#define MTDENS 1001 /* Random unused number. */ + +struct densities { + int code; + char *name; +} density_tbl[] = { + {0x00, "default"}, + {0x01, "NRZI (800 bpi)"}, + {0x02, "PE (1600 bpi)"}, + {0x03, "GCR (6250 bpi)"}, + {0x05, "QIC-45/60 (GCR, 8000 bpi)"}, + {0x06, "PE (3200 bpi)"}, + {0x07, "IMFM (6400 bpi)"}, + {0x08, "GCR (8000 bpi)"}, + {0x09, "GCR /37871 bpi)"}, + {0x0a, "MFM (6667 bpi)"}, + {0x0b, "PE (1600 bpi)"}, + {0x0c, "GCR (12960 bpi)"}, + {0x0d, "GCR (25380 bpi)"}, + {0x0f, "QIC-120 (GCR 10000 bpi)"}, + {0x10, "QIC-150/250 (GCR 10000 bpi)"}, + {0x11, "QIC-320/525 (GCR 16000 bpi)"}, + {0x12, "QIC-1350 (RLL 51667 bpi)"}, + {0x13, "DDS (61000 bpi)"}, + {0x14, "EXB-8200 (RLL 43245 bpi)"}, + {0x15, "EXB-8500 (RLL 45434 bpi)"}, + {0x16, "MFM 10000 bpi"}, + {0x17, "MFM 42500 bpi"}, + {0x24, "DDS-2"}, + {140, "EXB-8505 compressed"}, + {144, "EXB-8205 compressed"}, + {-1, NULL}}; +#endif char *opnames[] = { @@ -107,6 +190,8 @@ #endif #ifdef MTEOM "eom", + "eod", + "seod", #endif #ifdef MTRETEN "retension", @@ -121,6 +206,39 @@ #ifdef MTSEEK "seek", #endif +#ifdef MTTELL + "tell", +#endif +#ifdef MTFSS + "fss", +#endif +#ifdef MTBSS + "bss", +#endif +#ifdef MTWSM + "wset", +#endif +#ifdef MTSETBLK + "setblk", +#endif +#ifdef MTSETDENSITY + "setdensity", +#endif +#ifdef MTSETDRVBUFFER + "drvbuffer", +#ifdef MT_ST_BOOLEANS + "stoptions", +#endif +#ifdef MT_ST_WRITE_THRESHOLD + "stwrthreshold", +#endif +#endif +#ifdef MTDATCOMP + "datcompression", +#endif +#ifdef MTDENS + "densities", +#endif NULL }; @@ -134,6 +252,8 @@ #endif #ifdef MTEOM MTEOM, + MTEOM, + MTEOM, #endif #ifdef MTRETEN MTRETEN, @@ -148,9 +268,68 @@ #ifdef MTSEEK MTSEEK, #endif +#ifdef MTTELL + MTTELL, +#endif +#ifdef MTFSS + MTFSS, +#endif +#ifdef MTBSS + MTBSS, +#endif +#ifdef MTWSM + MTWSM, +#endif +#ifdef MTSETBLK + MTSETBLK, +#endif +#ifdef MTSETDENSITY + MTSETDENSITY, +#endif +#ifdef MTSETDRVBUFFER + MTSETDRVBUFFER, +#ifdef MT_ST_BOOLEANS + MTSETDRVBUFFER, +#endif +#ifdef MT_ST_WRITE_THRESHOLD + MTSETDRVBUFFER, +#endif +#endif +#ifdef MTDATCOMP + MTDATCOMP, +#endif +#ifdef MTDENS + MTDENS, +#endif 0 }; +char *cbnames[] = +{ +#ifdef MT_ST_BOOLEANS + "stoptions", +#endif +#ifdef MT_ST_WRITE_THRESHOLD + "stwrthreshold", +#endif + NULL +}; + +int count_bits[] = +{ +#ifdef MT_ST_BOOLEANS + MT_ST_BOOLEANS, +#endif +#ifdef MT_ST_WRITE_THRESHOLD + MT_ST_WRITE_THRESHOLD, +#endif + 0 +}; + +#ifdef MT_TAPE_INFO + struct mt_tape_info tapes[] = MT_TAPE_INFO; +#endif + /* If nonzero, don't consider file names that contain a `:' to be on remote hosts; all files are local. Always zero for mt; since when do local device names contain colons? */ @@ -246,10 +425,29 @@ #endif } +#ifdef MTDENS + if (operation == MTDENS) + { + printf("Some SCSI tape density codes:\ncode explanation\n"); + for (i=0; density_tbl[i].code >= 0; i++) + printf("0x%02x %s\n", density_tbl[i].code, density_tbl[i].name); + exit (0); + } +#endif + if ( (operation == MTWEOF) #ifdef MTERASE || (operation == MTERASE) #endif +#ifdef MTWSM + || (operation == MTWSM) +#endif +#ifdef MTSETDRVBUFFER + || (operation == MTSETDRVBUFFER) +#endif +#ifdef MTDATCOMP + || (operation == MTDATCOMP) +#endif ) tapedesc = rmtopen (tapedev, O_WRONLY, 0, rsh_command_option); else @@ -258,15 +456,27 @@ error (1, errno, "%s", tapedev); check_type (tapedev, tapedesc); - if (operation == MTASF) - { - perform_operation (tapedev, tapedesc, MTREW, 1); - operation = MTFSF; - } - perform_operation (tapedev, tapedesc, operation, count); - if (operation == MTNOP) - print_status (tapedev, tapedesc); - +#ifdef MTDATCOMP + if (operation == MTDATCOMP) + do_dat_compression(tapedev, tapedesc, count); + else +#endif +#ifdef MTTELL + if (operation == MTTELL) + print_position (tapedev, tapedesc); + else +#endif + { + if (operation == MTASF) + { + perform_operation (tapedev, tapedesc, MTREW, 1); + operation = MTFSF; + } + perform_operation (tapedev, tapedesc, operation, count); + if (operation == MTNOP) + print_status (tapedev, tapedesc); + } + if (rmtclose (tapedesc) == -1) error (2, errno, "%s", tapedev); @@ -312,10 +522,22 @@ int desc; { struct mtget status; +#ifdef MT_TAPE_INFO + struct mt_tape_info *mt; +#endif if (rmtioctl (desc, MTIOCGET, &status) == -1) error (2, errno, "%s", dev); +#ifdef MT_TAPE_INFO + for (mt = tapes; mt->t_type; mt++) + if (mt->t_type == status.mt_type) break; + if (mt->t_type != 0) + { + printf ("drive type = %s\n", mt->t_name); + } + else +#endif printf ("drive type = %d\n", (int) status.mt_type); #if defined(hpux) || defined(__hpux) printf ("drive status (high) = %d\n", (int) status.mt_dsreg1); @@ -329,6 +551,57 @@ printf ("file number = %d\n", (int) status.mt_fileno); printf ("block number = %d\n", (int) status.mt_blkno); #endif +#if defined(linux) || defined(__linux) + if (status.mt_type == MT_ISSCSI1 || + status.mt_type == MT_ISSCSI2) + { + int dens, i; + char *density; + dens = (status.mt_dsreg & MT_ST_DENSITY_MASK) >> MT_ST_DENSITY_SHIFT; + density = "unknown"; + for (i=0; density_tbl[i].code >= 0; i++) + if (density_tbl[i].code == dens) + { + density = density_tbl[i].name; + break; + } + printf("Tape block size %d bytes. Density code 0x%x (%s).\n", + ((status.mt_dsreg & MT_ST_BLKSIZE_MASK) >> MT_ST_BLKSIZE_SHIFT), + dens, density); + + printf("Soft error count since last status=%d\n", + (status.mt_erreg & MT_ST_SOFTERR_MASK) >> MT_ST_SOFTERR_SHIFT); + printf("General status bits on (%x):\n", status.mt_gstat); + if (GMT_EOF(status.mt_gstat)) + printf(" EOF"); + if (GMT_BOT(status.mt_gstat)) + printf(" BOT"); + if (GMT_EOT(status.mt_gstat)) + printf(" EOT"); + if (GMT_SM(status.mt_gstat)) + printf(" SM"); + if (GMT_EOD(status.mt_gstat)) + printf(" EOD"); + if (GMT_WR_PROT(status.mt_gstat)) + printf(" WR_PROT"); + if (GMT_ONLINE(status.mt_gstat)) + printf(" ONLINE"); + if (GMT_D_6250(status.mt_gstat)) + printf(" D_6250"); + if (GMT_D_1600(status.mt_gstat)) + printf(" D_1600"); + if (GMT_D_800(status.mt_gstat)) + printf(" D_800"); + if (GMT_DR_OPEN(status.mt_gstat)) + printf(" DR_OPEN"); + if (GMT_IM_REP_EN(status.mt_gstat)) + printf(" IM_REP_EN"); + } + else + { + printf("gstat = %0x\n", status.mt_gstat); + } +#endif } void @@ -342,3 +615,118 @@ program_name); exit (status); } + +#if defined(linux) || defined(__linux) +/*** Get and set the DAT compression (Mode Page 15) ***/ + +#define MODE_SENSE 0x1a +#define MODE_SELECT 0x15 + +int +read_mode_page(int fn, int page, int length, unsigned char *buffer, + int do_mask) +{ + int result, *ip; + unsigned char tmpbuffer[30], *cmd; + + memset(tmpbuffer, 0, 14); + ip = (int *)&(tmpbuffer[0]); + *ip = 0; + *(ip+1) = length + 4; + + cmd = &(tmpbuffer[8]); + cmd[0] = MODE_SENSE; + cmd[1] = 8; + cmd[2] = page; + if (do_mask) + cmd[2] |= 0x40; /* Get changeable parameter mask */ + cmd[4] = length + 4; + + result = ioctl(fn, 1, tmpbuffer); + if (result) { + fprintf(stderr, "Can't read mode page. Are you sure you are root?\n"); + return 0; + } + memcpy(buffer, tmpbuffer + 8, length + 4); + return 1; +} + + +int +write_mode_page(int fn, int page, int length, unsigned char *buffer) +{ + int result, *ip; + unsigned char tmpbuffer[40], *cmd; + + memset(tmpbuffer, 0, 14); + ip = (int *)&(tmpbuffer[0]); + *ip = length + 4; + *(ip+1) = 0; + + cmd = &(tmpbuffer[8]); + cmd[0] = MODE_SELECT; + cmd[1] = 0x10; + cmd[4] = length + 4; + + memcpy(tmpbuffer + 14, buffer, length + 4); + tmpbuffer[14] = 0; /* reserved data length */ + tmpbuffer[18] &= 0x3f; /* reserved bits in page code byte */ + + result = ioctl(fn, 1, tmpbuffer); + if (result) { + fprintf(stderr, "Can't write mode page.\n"); + return 0; + } + return 1; +} + + +int +do_dat_compression(char *dev, int fn, int count) +{ + int i; + unsigned char buffer[30], mask[30]; + + if (!read_mode_page(fn, 0x0f, 16, buffer, 0)) { + error (2, errno, "%s", dev); + } + + if (count != 1) { + if (count == 0) + buffer[4+2] &= 0x7f; + else + buffer[4+2] |= 0x80; + if (read_mode_page(fn, 0x0f, 16, mask, 1)) + for (i=2; i < 16; i++) + buffer[4+i] != mask[4+i]; + if (!write_mode_page(fn, 0x0f, 16, buffer)) { + error (2, errno, "%s", dev); + } + if (!read_mode_page(fn, 0x0f, 16, buffer, 0)) { /* Re-read to check */ + error (2, errno, "%s", dev); + } + } + + if (buffer[4+2] & 0x80) + printf("Compression on.\n"); + else + printf("Compression off.\n"); + + return 1; +} +#endif + +#ifdef MTTELL +void +print_position (dev, desc) + char *dev; + int desc; +{ + struct mtpos position; + + if (rmtioctl (desc, MTIOCPOS, &position) == -1) + error (2, errno, "%s", dev); + printf("At block %d.\n", position.mt_blkno); + +} +#endif --- rmt.8 +++ rmt.8 2000/12/03 14:36:49 @@ -0,0 +1,223 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)rmt.8 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt RMT 8 +.Os BSD 4.2 +.Sh NAME +.Nm rmt +.Nd remote magtape protocol module +.Sh SYNOPSIS +.Nm rmt +.Sh DESCRIPTION +.Nm Rmt +is a program used by tar, cpio, mt, and the remote dump and restore +programs in manipulating a magnetic tape drive through an interprocess +communication connection. +.Nm Rmt +is normally started up with an +.Xr rexec 3 +or +.Xr rcmd 3 +call or the +.Xr rsh 1 +command. +.Pp +The +.Nm rmt +program accepts requests specific to the manipulation of +magnetic tapes, performs the commands, then responds with +a status indication. All responses are in +.Tn ASCII +and in +one of two forms. +Successful commands have responses of: +.Bd -filled -offset indent +.Sm off +.Sy A Ar number No \en +.Sm on +.Ed +.Pp +.Ar Number +is an +.Tn ASCII +representation of a decimal number. +Unsuccessful commands are responded to with: +.Bd -filled -offset indent +.Sm off +.Xo Sy E Ar error-number +.No \en Ar error-message +.No \en +.Xc +.Sm on +.Ed +.Pp +.Ar Error-number +is one of the possible error +numbers described in +.Xr intro 2 +and +.Ar error-message +is the corresponding error string as printed +from a call to +.Xr perror 3 . +The protocol is comprised of the +following commands, which are sent as indicated - no spaces are supplied +between the command and its arguments, or between its arguments, and +.Ql \en +indicates that a newline should be supplied: +.Bl -tag -width Ds +.Sm off +.It Xo Sy \&O Ar device +.No \en Ar mode No \en +.Xc +Open the specified +.Ar device +using the indicated +.Ar mode . +.Ar Device +is a full pathname and +.Ar mode +is an +.Tn ASCII +representation of a decimal +number suitable for passing to +.Xr open 2 . +If a device had already been opened, it is +closed before a new open is performed. +.It Xo Sy C Ar device No \en +.Xc +Close the currently open device. The +.Ar device +specified is ignored. +.It Xo Sy L +.Ar whence No \en +.Ar offset No \en +.Xc +.Sm on +Perform an +.Xr lseek 2 +operation using the specified parameters. +The response value is that returned from the +.Xr lseek +call. +.Sm off +.It Sy W Ar count No \en +.Sm on +Write data onto the open device. +.Nm Rmt +reads +.Ar count +bytes from the connection, aborting if +a premature end-of-file is encountered. +The response value is that returned from +the +.Xr write 2 +call. +.Sm off +.It Sy R Ar count No \en +.Sm on +Read +.Ar count +bytes of data from the open device. +If +.Ar count +exceeds the size of the data buffer (10 kilobytes), it is +truncated to the data buffer size. +.Nm rmt +then performs the requested +.Xr read 2 +and responds with +.Sm off +.Sy A Ar count-read No \en +.Sm on +if the read was +successful; otherwise an error in the +standard format is returned. If the read +was successful, the data read is then sent. +.Sm off +.It Xo Sy I Ar operation +.No \en Ar count No \en +.Xc +.Sm on +Perform a +.Dv MTIOCOP +.Xr ioctl 2 +command using the specified parameters. +The parameters are interpreted as the +.Tn ASCII +representations of the decimal values +to place in the +.Ar mt_op +and +.Ar mt_count +fields of the structure used in the +.Xr ioctl +call. The return value is the +.Ar count +parameter when the operation is successful. +.It Sy S +Return the status of the open device, as +obtained with a +.Dv MTIOCGET +.Xr ioctl +call. If the operation was successful, +an ``ack'' is sent with the size of the +status buffer, then the status buffer is +sent (in binary). +.El +.Sm on +.Pp +Any other command causes +.Nm rmt +to exit. +.Sh DIAGNOSTICS +All responses are of the form described above. +.Sh SEE ALSO +.Xr tar 1 , +.Xr cpio 1 , +.Xr mt 1 , +.Xr rsh 1 , +.Xr rcmd 3 , +.Xr rexec 3 , +.Xr mtio 4 , +.Xr rdump 8 , +.Xr rrestore 8 +.Sh BUGS +People should be discouraged from using this for a remote +file access protocol. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . --- userspec.c +++ userspec.c 2000/12/03 14:40:31 @@ -63,8 +63,10 @@ struct group *getgrgid (); #endif -#ifdef _POSIX_SOURCE +#ifndef HAVE_ENDPWENT #define endpwent() +#endif +#ifndef HAVE_ENDGRENT #define endgrent() #endif --- util.c +++ util.c 2000/12/03 14:40:45 @@ -42,7 +42,9 @@ static void tape_fill_input_buffer P_((int in_des, int num_bytes)); static int disk_fill_input_buffer P_((int in_des, int num_bytes)); static void hash_insert (); -static void write_nuls_to_file P_((long num_bytes, int out_des)); +typedef void (*buffered_write_f) P_((char * in_buf, int out_des, long num_bytes)); +static void write_nuls_to_file P_((long num_bytes, int out_des, + buffered_write_f writef)); /* Write `output_size' bytes of `output_buffer' to file descriptor OUT_DES and reset `output_size' and `out_buff'. */ @@ -497,7 +499,7 @@ else error (0, 0, "Read error at byte %ld in file %s, padding with zeros", original_num_bytes - num_bytes, filename); - write_nuls_to_file (num_bytes, out_des); + write_nuls_to_file (num_bytes, out_des, tape_buffered_write); break; } size = (input_size < num_bytes) ? input_size : num_bytes; @@ -544,7 +546,7 @@ else error (0, 0, "Read error at byte %ld in file %s, padding with zeros", original_num_bytes - num_bytes, filename); - write_nuls_to_file (num_bytes, out_des); + write_nuls_to_file (num_bytes, out_des, disk_buffered_write); break; } size = (input_size < num_bytes) ? input_size : num_bytes; @@ -697,8 +699,8 @@ temp = (temp + 1) % hash_size) { if (hash_table[temp]->inode == node_num - && hash_table[start]->major_num == major_num - && hash_table[start]->minor_num == minor_num) + && hash_table[temp]->major_num == major_num + && hash_table[temp]->minor_num == minor_num) return hash_table[temp]->file_name; } } @@ -1320,24 +1322,17 @@ } static void -write_nuls_to_file (num_bytes, out_des) +write_nuls_to_file (num_bytes, out_des, writef) long num_bytes; int out_des; + buffered_write_f writef; { - long blocks; - long extra_bytes; - long i; - - blocks = num_bytes / 512; - extra_bytes = num_bytes % 512; - for (i = 0; i < extra_bytes; ++i) - { - if (write (out_des, zeros_512, 512) != 512) - error (1, errno, "error writing NUL's"); - } + long blocks = num_bytes / 512; + long extra_bytes = num_bytes % 512; + + while (blocks-- > 0) + (*writef)(zeros_512, out_des, 512); if (extra_bytes != 0) - { - if (write (out_des, zeros_512, extra_bytes) != extra_bytes) - error (1, errno, "error writing NUL's"); - } + (*writef)(zeros_512, out_des, extra_bytes); } +