📄 output-tape.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: James da Silva, Systems Design and Analysis Group * Computer Science Department * University of Maryland at College Park *//* NOTE: this driver is *deprecated* and should not be used. See the Device API * in device-src/ for the new implementation. *//* * $Id: output-tape.c,v 1.18 2006/08/22 14:19:39 martinea Exp $ * * tapeio.c virtual tape interface for normal tape drives. */#ifdef NO_AMANDA#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/wait.h>#else#include "amanda.h"#include "tapeio.h"#endif#include "output-tape.h"#ifndef NO_AMANDA#include "fileheader.h"#endif#ifndef R_OK#define R_OK 4#define W_OK 2#endif/*=======================================================================** Here are the ioctl() interface routines, which are #ifdef-ed** heavily by platform.=======================================================================*/#if defined(HAVE_BROKEN_FSF) /* { *//* * tape_tapefd_fsf -- handle systems that have a broken fsf operation * and cannot do an fsf operation unless they are positioned at a tape * mark (or BOT). Sheesh! This shows up in amrestore as I/O errors * when skipping. */inttape_tapefd_fsf( int fd, off_t count){ size_t buflen; char *buffer = NULL; int len = 0; buflen = getconf_readblocksize() * 1024; buffer = alloc(buflen); while(--count >= 0) { while((len = tapefd_read(fd, buffer, buflen)) > 0) {} if(len < 0) { break; } } amfree(buffer); return len;}#endif /* } */#ifdef WANT_TAPE_UWARE /* { */#include <sys/tape.h>/* * Rewind a tape to the beginning. */inttape_tapefd_rewind( int fd){ int st; return ioctl(fd, T_RWD, &st);}/* * Rewind and unload a tape. */inttape_tapefd_unload( int fd){ int st; return ioctl(fd, T_OFFL, &st);}#if !defined(HAVE_BROKEN_FSF)/* * Forward space the tape device count files. */inttape_tapefd_fsf( int fd, off_t count){ int st; int status; while (--count >= 0) { if ((status = ioctl(fd, T_SFF, &st)) != 0) { break; } } return status;}#endif/* * Write some number of end of file marks (a.k.a. tape marks). */inttape_tapefd_weof( int fd, off_t count){ int st; int status; while (--count >= (off_t)0) { if ((status = ioctl(fd, T_WRFILEM, &st)) != 0) { break; } } return status;}#else /* }{ */#ifdef WANT_TAPE_AIX /* { */#include <sys/tape.h>/* * Rewind a tape to the beginning. */inttape_tapefd_rewind( int fd){ struct stop st; st.st_op = STREW; st.st_count = 1; return ioctl(fd, STIOCTOP, &st);}/* * Rewind and unload a tape. */inttape_tapefd_unload( int fd){ struct stop st; st.st_op = STOFFL; st.st_count = 1; return ioctl(fd, STIOCTOP, &st);}#if !defined(HAVE_BROKEN_FSF)/* * Forward space the tape device count files. */inttape_tapefd_fsf( int fd, off_t count){ struct stop st; if ((count > (off_t)INT_MAX) || (count < (off_t)INT_MIN)) {#ifdef EOVERFLOW errno = EOVERFLOW;#else errno = EINVAL;#endif return -1; } st.st_op = STFSF; st.st_count = (int)count; return ioctl(fd, STIOCTOP, &st);}#endif/* * Write some number of end of file marks (a.k.a. tape marks). */inttape_tapefd_weof( int fd, off_t count){ struct stop st; if ((count > (off_t)INT_MAX) || (count < (off_t)INT_MIN)) {#ifdef EOVERFLOW errno = EOVERFLOW;#else errno = EINVAL;#endif return -1; } st.st_op = STWEOF; st.st_count = (int)count; return ioctl(fd, STIOCTOP, &st);}#else /* WANT_TAPE_AIX */ /* }{ */#ifdef WANT_TAPE_XENIX /* { */#include <sys/tape.h>/* * Rewind a tape to the beginning. */inttape_tapefd_rewind( int fd){ int st; return ioctl(fd, MT_REWIND, &st);}/* * Rewind and unload a tape. */inttape_tapefd_unload( int fd){ int st; int f;#ifdef MT_OFFLINE f = MT_OFFLINE;#else#ifdef MT_UNLOAD f = MT_UNLOAD;#else f = syntax error;#endif#endif return ioctl(fd, f, &st);}#if !defined(HAVE_BROKEN_FSF)/* * Forward space the tape device count files. */inttape_tapefd_fsf( int fd, off_t count){ int st; int status; while (--count >= 0) { if ((status = ioctl(fd, MT_RFM, &st)) != 0) { break; } } return status;}#endif/* * Write some number of end of file marks (a.k.a. tape marks). */inttape_tapefd_weof( int fd, off_t count){ int st; int c; int status; while (--count >= 0) { if ((status = ioctl(fd, MT_WFM, &st)) != 0) { break; } } return status;}#else /* ! WANT_TAPE_AIX && !WANT_TAPE_XENIX */ /* }{ */#include <sys/mtio.h>/* * Rewind a tape to the beginning. */inttape_tapefd_rewind( int fd){ struct mtop mt; int rc=-1, cnt; mt.mt_op = MTREW; mt.mt_count = 1; /* * EXB-8200 drive on FreeBSD can fail to rewind, but retrying won't * hurt, and it will usually even work! */ for(cnt = 10; cnt >= 0; --cnt) { if ((rc = ioctl(fd, MTIOCTOP, &mt)) == 0) { break; } if (cnt) { sleep(3); } } return rc;}/* * Rewind and unload a tape. */inttape_tapefd_unload( int fd){ struct mtop mt; int rc=-1, cnt;#ifdef MTUNLOAD mt.mt_op = MTUNLOAD;#else#ifdef MTOFFL mt.mt_op = MTOFFL;#else mt.mt_op = syntax error;#endif#endif mt.mt_count = 1; /* * EXB-8200 drive on FreeBSD can fail to unload, but retrying won't * hurt, and it will usually even work! */ for(cnt = 10; cnt >= 0; --cnt) { if ((rc = ioctl(fd, MTIOCTOP, &mt)) == 0) { break; } if (cnt) { sleep(3); } } return rc;}#if !defined(HAVE_BROKEN_FSF)/* * Forward space the tape device count files. */inttape_tapefd_fsf( int fd, off_t count){ struct mtop mt; if ((count > (off_t)INT_MAX) || (count < (off_t)INT_MIN)) {#ifdef EOVERFLOW errno = EOVERFLOW;#else errno = EINVAL;#endif return -1; } mt.mt_op = MTFSF; mt.mt_count = (int)count; return ioctl(fd, MTIOCTOP, &mt);}#endif/* * Write some number of end of file marks (a.k.a. tape marks). * * write <count> filemarks on the tape. */inttape_tapefd_weof( int fd, off_t count){ struct mtop mt; if ((count > (off_t)INT_MAX) || (count < (off_t)INT_MIN)) {#ifdef EOVERFLOW errno = EOVERFLOW;#else errno = EINVAL;#endif return -1; } mt.mt_op = MTWEOF; mt.mt_count = (int)count; return ioctl(fd, MTIOCTOP, &mt);}#endif /* !WANT_TAPE_XENIX */ /* } */#endif /* !WANT_TAPE_AIX */ /* } */#endif /* !WANT_TAPE_UWARE */ /* } *//* * At this point we have pulled in every conceivable #include file :-), * so now come the more general routines with minimal #ifdef-ing. */#ifdef HAVE_LINUX_ZFTAPE_H/* * is_zftape(filename) checks if filename is a valid ftape device name. */intis_zftape( const char *filename){ if (strncmp(filename, "/dev/nftape", 11) == 0) return(1); if (strncmp(filename, "/dev/nqft", 9) == 0) return(1); if (strncmp(filename, "/dev/nrft", 9) == 0) return(1); return(0);}#endif /* HAVE_LINUX_ZFTAPE_H */inttape_tape_open( char *filename, int flags, mode_t mask){ int ret; time_t timeout = 200; unsigned delay = 2; if ((flags & 3) != O_RDONLY) { flags &= ~3; flags |= O_RDWR; } ret = open(filename, flags, mask); while (ret < 0) { if ((errno != EAGAIN) && (errno != EBUSY) && (errno != EINTR)) { /* * Open failed completely: just return */ g_fprintf(stderr, _("Opening tapedev %s: got error %s.\n"), filename, strerror(errno)); return -1; } /* * if tape open fails with errno==EAGAIN, EBUSY or EINTR, it * may be worth retrying a few seconds later. */ timeout -= delay; if (timeout <= 0) { /* Open failed: just return */ g_fprintf(stderr, _("Opening tapedev %s: not ready.\n"), filename); return -1; } if (delay < 16) delay *= 2; sleep(delay); ret = open(filename, flags, mask); }#ifdef MTIOCGET /* Now check that we opened a tape device. */ { struct mtget mt; memset(&mt, 0, SIZEOF(mt)); if (ioctl(ret, MTIOCGET, &mt) < 0) { close(ret); g_fprintf(stderr, _("tapedev %s is not a tape device!\n"), filename); return -1; }#ifdef GMT_ONLINE if (!GMT_ONLINE(mt.mt_gstat)) { close(ret); g_fprintf(stderr, _("tapedev %s is offline or has no loaded tape.\n"), filename); return -1; }#endif /* GMT_ONLINE */ }#endif /* MTIOCGET */#ifdef HAVE_LINUX_ZFTAPE_H /* * switch the block size for the zftape driver (3.04d) * (its default is 10kb and not 32kb) * A. Gebhardt <albrecht.gebhardt@uni-klu.ac.at> */ if (is_zftape(filename) == 1) { struct mtop mt; mt.mt_op = MTSETBLK; mt.mt_count = 32 * 1024; /* should be blocksize ??? */ ioctl(ret, MTIOCTOP, &mt); }#endif /* HAVE_LINUX_ZFTAPE_H */ return ret;}ssize_ttape_tapefd_read( int fd, void *buffer, size_t count){ return read(fd, buffer, count);}ssize_ttape_tapefd_write( int fd, const void *buffer, size_t count){ return write(fd, buffer, count);}inttape_tapefd_close( int fd){ return close(fd);} voidtape_tapefd_resetofs( int fd){ /* * this *should* be a no-op on the tape, but resets the kernel's view * of the file offset, preventing it from barfing should we pass the * filesize limit (eg OSes with 2 GB filesize limits) on a long tape. */ if (lseek(fd, (off_t)0, SEEK_SET) < 0) { dbprintf(_("tape_tapefd_resetofs: lseek failed: <%s>\n"), strerror(errno)); }}inttape_tapefd_status( int fd, struct am_mt_status *stat){ int res; int anything_valid = 0;#if defined(MTIOCGET) struct mtget buf;#endif memset((void *)stat, 0, SIZEOF(*stat));#if defined(MTIOCGET) /* { */ res = ioctl(fd,MTIOCGET,&buf); if (res >= 0) { /*@ignore@*/#ifdef MT_ONL /* { */ /* IRIX-ish system */ anything_valid = 1; stat->online_valid = 1; stat->online = (0 != (buf.mt_dposn & MT_ONL)); stat->bot_valid = 1; stat->bot = (0 != (buf.mt_dposn & MT_BOT)); stat->eot_valid = 1; stat->eot = (0 != (buf.mt_dposn & MT_EOT)); stat->protected_valid = 1; stat->protected = (0 != (buf.mt_dposn & MT_WPROT));#else /* }{ */#ifdef GMT_ONLINE /* { */ /* Linux-ish system */ anything_valid = 1; stat->online_valid = 1; stat->online = (0 != GMT_ONLINE(buf.mt_gstat)); stat->bot_valid = 1; stat->bot = (0 != GMT_BOT(buf.mt_gstat)); stat->eot_valid = 1; stat->eot = (0 != GMT_EOT(buf.mt_gstat)); stat->protected_valid = 1; stat->protected = (0 != GMT_WR_PROT(buf.mt_gstat));#else /* }{ */#ifdef DEV_BOM /* { */ /* OSF1-ish system */ anything_valid = 1; stat->online_valid = 1; stat->online = (0 == (DEV_OFFLINE & buf.mt_dsreg)); stat->bot_valid = 1; stat->bot = (0 != (DEV_BOM & buf.mt_dsreg)); stat->protected_valid = 1; stat->protected = (0 != (DEV_WRTLCK & buf.mt_dsreg));#else /* }{ */ /* Solaris, minix, etc. */ anything_valid = 1; stat->online_valid = 1; stat->online = 1; /* ioctl fails otherwise */#ifdef HAVE_MT_DSREG stat->device_status_valid = 1; stat->device_status_size = SIZEOF(buf.mt_dsreg); stat->device_status = (unsigned long)buf.mt_dsreg;#endif#ifdef HAVE_MT_ERREG stat->error_status_valid = 1; stat->error_status_size = SIZEOF(buf.mt_erreg); stat->error_status = (unsigned long)buf.mt_erreg;#endif#if defined(HAVE_MT_FLAGS) && defined(MTF_SCSI) /* { */ /* * On Solaris, the file/block number fields are only valid if * the driver is SCSI. And in that case, the dsreg value is * not useful (it is a retry count). */ if(buf.mt_flags & MTF_SCSI) { stat->device_status_valid = 0;#ifdef HAVE_MT_FILENO stat->fileno_valid = 1; stat->fileno = (long)buf.mt_fileno;#endif#ifdef HAVE_MT_BLKNO stat->blkno_valid = 1; stat->blkno = (long)buf.mt_blkno;#endif }#endif /* } */#endif /* } */#endif /* } */#endif /* } */ /*@end@*/ }#endif /* } */ /* * If we did not find any valid information, do a stat on the device * and if that returns successfully, assume it is at least online. */ if(!anything_valid) { struct stat sbuf; res = fstat(fd, &sbuf); stat->online_valid = 1; stat->online = (char)(res == 0); } return res;}inttape_tape_stat( char *filename, struct stat *buf){ return stat(filename, buf);}inttape_tape_access( char *filename, int mode){ return access(filename, mode);}int tape_tapefd_can_fork( int fd){ (void)fd; /* Quiet unused parameter warning */ return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -