arg_t _ioctl(void) { inoptr ino; uint16_t dev; if ((ino = getinode(fd)) == NULLINODE) return -1; if (!(isdevice(ino))) { udata.u_error = ENOTTY; return -1; } if ((request & IOCTL_SUPER) && esuper()) return -1; if (!(getperm(ino) & OTH_WR)) { udata.u_error = EPERM; return -1; } dev = ino->c_node.i_addr[0]; /* top bit of request is reserved for kernel originated magic */ return d_ioctl(dev, request & 0x7FFF, data); }
/* * Backward space a record * * Returns: false on failure * true on success */ bool generic_tape_device::bsr(int num) { struct mtop mt_com; int status; if (!is_open()) { dev_errno = EBADF; Mmsg0(errmsg, _("Bad call to bsr_dev. Device not open\n")); Emsg0(M_FATAL, 0, errmsg); return false; } if (!has_cap(CAP_BSR)) { Mmsg1(errmsg, _("ioctl MTBSR not permitted on %s.\n"), prt_name); return false; } Dmsg0(100, "bsr_dev\n"); block_num -= num; clear_eof(); clear_eot(); mt_com.mt_op = MTBSR; mt_com.mt_count = num; status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status < 0) { berrno be; clrerror(mt_com.mt_op); Mmsg2(errmsg, _("ioctl MTBSR error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); } return status == 0; }
/* * Load medium in device * * Returns: true on success * false on failure */ bool generic_tape_device::load_dev() { #ifdef MTLOAD struct mtop mt_com; #endif if (m_fd < 0) { dev_errno = EBADF; Mmsg0(errmsg, _("Bad call to load_dev. Device not open\n")); Emsg0(M_FATAL, 0, errmsg); return false; } #ifndef MTLOAD Dmsg0(200, "stored: MTLOAD command not available\n"); berrno be; dev_errno = ENOTTY; /* function not available */ Mmsg2(errmsg, _("ioctl MTLOAD error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); return false; #else block_num = file = 0; file_size = 0; file_addr = 0; mt_com.mt_op = MTLOAD; mt_com.mt_count = 1; if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) { berrno be; dev_errno = errno; Mmsg2(errmsg, _("ioctl MTLOAD error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); return false; } return true; #endif }
/* * Backward space a file * * Returns: false on failure * true on success */ bool generic_tape_device::bsf(int num) { struct mtop mt_com; int status; if (!is_open()) { dev_errno = EBADF; Mmsg0(errmsg, _("Bad call to bsf. Device not open\n")); Emsg0(M_FATAL, 0, errmsg); return false; } Dmsg0(100, "bsf\n"); clear_eot(); clear_eof(); file -= num; file_addr = 0; file_size = 0; mt_com.mt_op = MTBSF; mt_com.mt_count = num; status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status < 0) { berrno be; clrerror(mt_com.mt_op); Mmsg2(errmsg, _("ioctl MTBSF error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); } return status == 0; }
/* Returns file position on tape or -1 */ int32_t DEVICE::get_os_tape_file() { struct mtget mt_stat; if (has_cap(CAP_MTIOCGET) && d_ioctl(m_fd, MTIOCGET, (char *)&mt_stat) == 0) { return mt_stat.mt_fileno; } return -1; }
int d_flush(uint16_t dev) { /* Not as clean as would be ideal : FIXME */ int r = d_ioctl(dev, BLKFLSBUF, 0); /* Not knowing the ioctl is not an offence */ if (r && udata.u_error == ENOTTY) { udata.u_error = 0; r = 0; } return r; }
void generic_tape_device::unlock_door() { #ifdef MTUNLOCK struct mtop mt_com; mt_com.mt_op = MTUNLOCK; mt_com.mt_count = 1; if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) { clrerror(mt_com.mt_op); } #endif }
/* * Foward space num records * * Returns: false on failure * true on success */ bool generic_tape_device::fsr(int num) { struct mtop mt_com; int status; if (!is_open()) { dev_errno = EBADF; Mmsg0(errmsg, _("Bad call to fsr. Device not open\n")); Emsg0(M_FATAL, 0, errmsg); return false; } if (!has_cap(CAP_FSR)) { Mmsg1(errmsg, _("ioctl MTFSR not permitted on %s.\n"), prt_name); return false; } Dmsg1(100, "fsr %d\n", num); mt_com.mt_op = MTFSR; mt_com.mt_count = num; status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status == 0) { clear_eof(); block_num += num; } else { berrno be; struct mtget mt_stat; clrerror(mt_com.mt_op); Dmsg1(100, "FSF fail: ERR=%s\n", be.bstrerror()); if (dev_get_os_pos(this, &mt_stat)) { Dmsg4(100, "Adjust from %d:%d to %d:%d\n", file, block_num, mt_stat.mt_fileno, mt_stat.mt_blkno); file = mt_stat.mt_fileno; block_num = mt_stat.mt_blkno; } else { if (at_eof()) { set_eot(); } else { set_ateof(); } } Mmsg3(errmsg, _("ioctl MTFSR %d error on %s. ERR=%s.\n"), num, prt_name, be.bstrerror()); } return status == 0; }
/* * Write an end of file on the device * * Returns: true on success * false on failure */ bool generic_tape_device::weof(int num) { struct mtop mt_com; int status; Dmsg1(129, "=== weof_dev=%s\n", prt_name); if (!is_open()) { dev_errno = EBADF; Mmsg0(errmsg, _("Bad call to weof_dev. Device not open\n")); Emsg0(M_FATAL, 0, errmsg); return false; } file_size = 0; if (!can_append()) { Mmsg0(errmsg, _("Attempt to WEOF on non-appendable Volume\n")); Emsg0(M_FATAL, 0, errmsg); return false; } clear_eof(); clear_eot(); mt_com.mt_op = MTWEOF; mt_com.mt_count = num; status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status == 0) { block_num = 0; file += num; file_addr = 0; } else { berrno be; clrerror(mt_com.mt_op); if (status == -1) { Mmsg2(errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); } } return status == 0; }
/* * Rewind device and put it offline * * Returns: true on success * false on failure */ bool generic_tape_device::offline() { struct mtop mt_com; state &= ~(ST_APPENDREADY | ST_READREADY | ST_EOT | ST_EOF | ST_WEOT); /* remove EOF/EOT flags */ block_num = file = 0; file_size = 0; file_addr = 0; unlock_door(); mt_com.mt_op = MTOFFL; mt_com.mt_count = 1; if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) { berrno be; dev_errno = errno; Mmsg2(errmsg, _("ioctl MTOFFL error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); return false; } Dmsg1(100, "Offlined device %s\n", prt_name); return true; }
/* * If implemented in system, clear the tape * error status. */ void DEVICE::clrerror(int func) { const char *msg = NULL; char buf[100]; dev_errno = errno; /* save errno */ if (errno == EIO) { VolCatInfo.VolCatErrors++; } if (!is_tape()) { return; } if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */ switch (func) { case -1: break; /* ignore message printed later */ case MTWEOF: msg = "WTWEOF"; clear_cap(CAP_EOF); /* turn off feature */ break; #ifdef MTEOM case MTEOM: msg = "WTEOM"; clear_cap(CAP_EOM); /* turn off feature */ break; #endif case MTFSF: msg = "MTFSF"; clear_cap(CAP_FSF); /* turn off feature */ break; case MTBSF: msg = "MTBSF"; clear_cap(CAP_BSF); /* turn off feature */ break; case MTFSR: msg = "MTFSR"; clear_cap(CAP_FSR); /* turn off feature */ break; case MTBSR: msg = "MTBSR"; clear_cap(CAP_BSR); /* turn off feature */ break; case MTREW: msg = "MTREW"; break; #ifdef MTSETBLK case MTSETBLK: msg = "MTSETBLK"; break; #endif #ifdef MTSETDRVBUFFER case MTSETDRVBUFFER: msg = "MTSETDRVBUFFER"; break; #endif #ifdef MTRESET case MTRESET: msg = "MTRESET"; break; #endif #ifdef MTSETBSIZ case MTSETBSIZ: msg = "MTSETBSIZ"; break; #endif #ifdef MTSRSZ case MTSRSZ: msg = "MTSRSZ"; break; #endif #ifdef MTLOAD case MTLOAD: msg = "MTLOAD"; break; #endif #ifdef MTUNLOCK case MTUNLOCK: msg = "MTUNLOCK"; break; #endif case MTOFFL: msg = "MTOFFL"; break; default: bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func); msg = buf; break; } if (msg != NULL) { dev_errno = ENOSYS; Mmsg1(errmsg, _("I/O function \"%s\" not supported on this device.\n"), msg); Emsg0(M_ERROR, 0, errmsg); } } /* * Now we try different methods of clearing the error * status on the drive so that it is not locked for * further operations. */ /* On some systems such as NetBSD, this clears all errors */ get_os_tape_file(); /* Found on Solaris */ #ifdef MTIOCLRERR { d_ioctl(m_fd, MTIOCLRERR); Dmsg0(200, "Did MTIOCLRERR\n"); } #endif /* Typically on FreeBSD */ #ifdef MTIOCERRSTAT { berrno be; /* Read and clear SCSI error status */ union mterrstat mt_errstat; Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev_errno, be.bstrerror(dev_errno)); d_ioctl(m_fd, MTIOCERRSTAT, (char *)&mt_errstat); } #endif /* Clear Subsystem Exception TRU64 */ #ifdef MTCSE { struct mtop mt_com; mt_com.mt_op = MTCSE; mt_com.mt_count = 1; /* Clear any error condition on the tape */ d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); Dmsg0(200, "Did MTCSE\n"); } #endif }
/* * Foward space a file * * Returns: true on success * false on failure */ bool generic_tape_device::fsf(int num) { int32_t os_file = 0; struct mtop mt_com; int status = 0; if (!is_open()) { dev_errno = EBADF; Mmsg0(errmsg, _("Bad call to fsf. Device not open\n")); Emsg0(M_FATAL, 0, errmsg); return false; } if (at_eot()) { dev_errno = 0; Mmsg1(errmsg, _("Device %s at End of Tape.\n"), prt_name); return false; } if (at_eof()) { Dmsg0(200, "ST_EOF set on entry to FSF\n"); } Dmsg0(100, "fsf\n"); block_num = 0; /* * If Fast forward space file is set, then we * use MTFSF to forward space and MTIOCGET * to get the file position. We assume that * the SCSI driver will ensure that we do not * forward space past the end of the medium. */ if (has_cap(CAP_FSF) && has_cap(CAP_MTIOCGET) && has_cap(CAP_FASTFSF)) { int my_errno = 0; mt_com.mt_op = MTFSF; mt_com.mt_count = num; status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status < 0) { my_errno = errno; /* save errno */ } else if ((os_file=get_os_tape_file()) < 0) { my_errno = errno; /* save errno */ } if (my_errno != 0) { berrno be; set_eot(); Dmsg0(200, "Set ST_EOT\n"); clrerror(mt_com.mt_op); Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), prt_name, be.bstrerror(my_errno)); Dmsg1(200, "%s", errmsg); return false; } Dmsg1(200, "fsf file=%d\n", os_file); set_ateof(); file = os_file; return true; /* * Here if CAP_FSF is set, and virtually all drives * these days support it, we read a record, then forward * space one file. Using this procedure, which is slow, * is the only way we can be sure that we don't read * two consecutive EOF marks, which means End of Data. */ } else if (has_cap(CAP_FSF)) { POOLMEM *rbuf; int rbuf_len; Dmsg0(200, "FSF has cap_fsf\n"); if (max_block_size == 0) { rbuf_len = DEFAULT_BLOCK_SIZE; } else { rbuf_len = max_block_size; } rbuf = get_memory(rbuf_len); mt_com.mt_op = MTFSF; mt_com.mt_count = 1; while (num-- && !at_eot()) { Dmsg0(100, "Doing read before fsf\n"); if ((status = this->read((char *)rbuf, rbuf_len)) < 0) { if (errno == ENOMEM) { /* tape record exceeds buf len */ status = rbuf_len; /* This is OK */ /* * On IBM drives, they return ENOSPC at EOM instead of EOF status */ } else if (at_eof() && errno == ENOSPC) { status = 0; } else if (has_cap(CAP_IOERRATEOM) && at_eof() && errno == EIO) { if (has_cap(CAP_IBMLINTAPE)) { Dmsg0(100, "Got EIO on read, checking lin_tape sense data\n"); if (check_scsi_at_eod(m_fd)) { Dmsg0(100, "Sense data confirms it's EOD\n"); status = 0; } else { Dmsg0(100, "Not at EOD, might be a real error. Check sense trace from lin_taped logs.\n"); set_eot(); clrerror(-1); Mmsg1(errmsg, _("read error on %s. ERR=Input/Output error.\n"), prt_name); break; } } else { Dmsg0(100, "Got EIO on read, assuming that's due to EOD\n"); status = 0; } } else { berrno be; set_eot(); clrerror(-1); Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev_errno, be.bstrerror()); Mmsg2(errmsg, _("read error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); Dmsg1(100, "%s", errmsg); break; } } if (status == 0) { /* EOF */ Dmsg1(100, "End of File mark from read. File=%d\n", file+1); /* * Two reads of zero means end of tape */ if (at_eof()) { set_eot(); Dmsg0(100, "Set ST_EOT\n"); break; } else { set_ateof(); continue; } } else { /* Got data */ clear_eot(); clear_eof(); } Dmsg0(100, "Doing MTFSF\n"); status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status < 0) { /* error => EOT */ berrno be; set_eot(); Dmsg0(100, "Set ST_EOT\n"); clrerror(mt_com.mt_op); Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); Dmsg0(100, "Got < 0 for MTFSF\n"); Dmsg1(100, "%s", errmsg); } else { set_ateof(); } } free_memory(rbuf); /* * No FSF, so use FSR to simulate it */ } else { Dmsg0(200, "Doing FSR for FSF\n"); while (num-- && !at_eot()) { fsr(INT32_MAX); /* returns -1 on EOF or EOT */ } if (at_eot()) { dev_errno = 0; Mmsg1(errmsg, _("Device %s at End of Tape.\n"), prt_name); status = -1; } else { status = 0; } } Dmsg1(200, "Return %d from FSF\n", status); if (at_eof()) { Dmsg0(200, "ST_EOF set on exit FSF\n"); } if (at_eot()) { Dmsg0(200, "ST_EOT set on exit FSF\n"); } Dmsg1(200, "Return from FSF file=%d\n", file); return status == 0; }
/* * Open a tape device */ void generic_tape_device::open_device(DCR *dcr, int omode) { file_size = 0; int timeout = max_open_wait; #if !defined(HAVE_WIN32) struct mtop mt_com; utime_t start_time = time(NULL); #endif mount(dcr, 1); /* do mount if required */ Dmsg0(100, "Open dev: device is tape\n"); get_autochanger_loaded_slot(dcr); open_mode = omode; set_mode(omode); if (timeout < 1) { timeout = 1; } errno = 0; Dmsg2(100, "Try open %s mode=%s\n", prt_name, mode_to_str(omode)); #if defined(HAVE_WIN32) /* * Windows Code */ if ((m_fd = d_open(dev_name, oflags, 0)) < 0) { dev_errno = errno; } #else /* * UNIX Code * * If busy retry each second for max_open_wait seconds */ for ( ;; ) { /* * Try non-blocking open */ m_fd = d_open(dev_name, oflags | O_NONBLOCK, 0); if (m_fd < 0) { berrno be; dev_errno = errno; Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n", prt_name, omode, oflags, errno, be.bstrerror()); } else { /* * Tape open, now rewind it */ Dmsg0(100, "Rewind after open\n"); mt_com.mt_op = MTREW; mt_com.mt_count = 1; /* * Rewind only if dev is a tape */ if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) { berrno be; dev_errno = errno; /* set error status from rewind */ d_close(m_fd); clear_opened(); Dmsg2(100, "Rewind error on %s close: ERR=%s\n", prt_name, be.bstrerror(dev_errno)); /* * If we get busy, device is probably rewinding, try again */ if (dev_errno != EBUSY) { break; /* error -- no medium */ } } else { /* * Got fd and rewind worked, so we must have medium in drive */ d_close(m_fd); m_fd = d_open(dev_name, oflags, 0); /* open normally */ if (m_fd < 0) { berrno be; dev_errno = errno; Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n", prt_name, omode, oflags, errno, be.bstrerror()); break; } dev_errno = 0; lock_door(); set_os_device_parameters(dcr); /* do system dependent stuff */ break; /* Successfully opened and rewound */ } } bmicrosleep(5, 0); /* * Exceed wait time ? */ if (time(NULL) - start_time >= max_open_wait) { break; /* yes, get out */ } } #endif if (!is_open()) { berrno be; Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"), prt_name, be.bstrerror(dev_errno)); Dmsg1(100, "%s", errmsg); } Dmsg1(100, "open dev: tape %d opened\n", m_fd); }
/* * Position device to end of medium (end of data) * * Returns: true on succes * false on error */ bool generic_tape_device::eod(DCR *dcr) { struct mtop mt_com; bool ok = true; int32_t os_file; if (m_fd < 0) { dev_errno = EBADF; Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), prt_name); return false; } #if defined (__digital__) && defined (__unix__) return fsf(VolCatInfo.VolCatFiles); #endif Dmsg0(100, "Enter eod\n"); if (at_eot()) { return true; } clear_eof(); /* remove EOF flag */ block_num = file = 0; file_size = 0; file_addr = 0; #ifdef MTEOM if (has_cap(CAP_FASTFSF) && !has_cap(CAP_EOM)) { Dmsg0(100,"Using FAST FSF for EOM\n"); /* * If unknown position, rewind */ if (get_os_tape_file() < 0) { if (!rewind(NULL)) { Dmsg0(100, "Rewind error\n"); return false; } } mt_com.mt_op = MTFSF; /* * ***FIXME*** fix code to handle case that INT16_MAX is not large enough. */ mt_com.mt_count = INT16_MAX; /* use big positive number */ if (mt_com.mt_count < 0) { mt_com.mt_count = INT16_MAX; /* brain damaged system */ } } if (has_cap(CAP_MTIOCGET) && (has_cap(CAP_FASTFSF) || has_cap(CAP_EOM))) { if (has_cap(CAP_EOM)) { Dmsg0(100,"Using EOM for EOM\n"); mt_com.mt_op = MTEOM; mt_com.mt_count = 1; } if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) { berrno be; clrerror(mt_com.mt_op); Dmsg1(50, "ioctl error: %s\n", be.bstrerror()); update_pos(dcr); Mmsg2(errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); Dmsg0(100, errmsg); return false; } os_file = get_os_tape_file(); if (os_file < 0) { berrno be; clrerror(-1); Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); Dmsg0(100, errmsg); return false; } Dmsg1(100, "EOD file=%d\n", os_file); set_ateof(); file = os_file; } else { #endif /* * Rewind then use FSF until EOT reached */ if (!rewind(NULL)) { Dmsg0(100, "Rewind error.\n"); return false; } /* * Move file by file to the end of the tape */ int file_num; for (file_num=file; !at_eot(); file_num++) { Dmsg0(200, "eod: doing fsf 1\n"); if (!fsf(1)) { Dmsg0(100, "fsf error.\n"); return false; } /* * Avoid infinite loop by ensuring we advance. */ if (!at_eot() && file_num == (int)file) { Dmsg1(100, "fsf did not advance from file %d\n", file_num); set_ateof(); os_file = get_os_tape_file(); if (os_file >= 0) { Dmsg2(100, "Adjust file from %d to %d\n", file_num, os_file); file = os_file; } break; } } #ifdef MTEOM } #endif /* * Some drivers leave us after second EOF when doing MTEOM, so we must backup * so that appending overwrites the second EOF. */ if (has_cap(CAP_BSFATEOM)) { /* * Backup over EOF */ ok = bsf(1); /* * If BSF worked and fileno is known (not -1), set file */ os_file = get_os_tape_file(); if (os_file >= 0) { Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", file , os_file); file = os_file; } else { file++; /* wing it -- not correct on all OSes */ } } else { update_pos(dcr); /* update position */ } Dmsg1(200, "EOD dev->file=%d\n", file); return ok; }
uint32_t generic_tape_device::status_dev() { struct mtget mt_stat; uint32_t status = 0; if (state & (ST_EOT | ST_WEOT)) { status |= BMT_EOD; Pmsg0(-20, " EOD"); } if (state & ST_EOF) { status |= BMT_EOF; Pmsg0(-20, " EOF"); } status |= BMT_TAPE; Pmsg0(-20,_(" Bareos status:")); Pmsg2(-20,_(" file=%d block=%d\n"), file, block_num); if (d_ioctl(m_fd, MTIOCGET, (char *)&mt_stat) < 0) { berrno be; dev_errno = errno; Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), print_name(), be.bstrerror()); return 0; } Pmsg0(-20, _(" Device status:")); #if defined(HAVE_LINUX_OS) if (GMT_EOF(mt_stat.mt_gstat)) { status |= BMT_EOF; Pmsg0(-20, " EOF"); } if (GMT_BOT(mt_stat.mt_gstat)) { status |= BMT_BOT; Pmsg0(-20, " BOT"); } if (GMT_EOT(mt_stat.mt_gstat)) { status |= BMT_EOT; Pmsg0(-20, " EOT"); } if (GMT_SM(mt_stat.mt_gstat)) { status |= BMT_SM; Pmsg0(-20, " SM"); } if (GMT_EOD(mt_stat.mt_gstat)) { status |= BMT_EOD; Pmsg0(-20, " EOD"); } if (GMT_WR_PROT(mt_stat.mt_gstat)) { status |= BMT_WR_PROT; Pmsg0(-20, " WR_PROT"); } if (GMT_ONLINE(mt_stat.mt_gstat)) { status |= BMT_ONLINE; Pmsg0(-20, " ONLINE"); } if (GMT_DR_OPEN(mt_stat.mt_gstat)) { status |= BMT_DR_OPEN; Pmsg0(-20, " DR_OPEN"); } if (GMT_IM_REP_EN(mt_stat.mt_gstat)) { status |= BMT_IM_REP_EN; Pmsg0(-20, " IM_REP_EN"); } #elif defined(HAVE_WIN32) if (GMT_EOF(mt_stat.mt_gstat)) { status |= BMT_EOF; Pmsg0(-20, " EOF"); } if (GMT_BOT(mt_stat.mt_gstat)) { status |= BMT_BOT; Pmsg0(-20, " BOT"); } if (GMT_EOT(mt_stat.mt_gstat)) { status |= BMT_EOT; Pmsg0(-20, " EOT"); } if (GMT_EOD(mt_stat.mt_gstat)) { status |= BMT_EOD; Pmsg0(-20, " EOD"); } if (GMT_WR_PROT(mt_stat.mt_gstat)) { status |= BMT_WR_PROT; Pmsg0(-20, " WR_PROT"); } if (GMT_ONLINE(mt_stat.mt_gstat)) { status |= BMT_ONLINE; Pmsg0(-20, " ONLINE"); } if (GMT_DR_OPEN(mt_stat.mt_gstat)) { status |= BMT_DR_OPEN; Pmsg0(-20, " DR_OPEN"); } if (GMT_IM_REP_EN(mt_stat.mt_gstat)) { status |= BMT_IM_REP_EN; Pmsg0(-20, " IM_REP_EN"); } #endif /* HAVE_LINUX_OS || HAVE_WIN32 */ if (has_cap(CAP_MTIOCGET)) { Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno); } else { Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1); } return status; }
/* * Rewind the device. * * Returns: true on success * false on failure */ bool generic_tape_device::rewind(DCR *dcr) { struct mtop mt_com; unsigned int i; bool first = true; Dmsg3(400, "rewind res=%d fd=%d %s\n", num_reserved(), m_fd, prt_name); state &= ~(ST_EOT | ST_EOF | ST_WEOT); /* Remove EOF/EOT flags */ block_num = file = 0; file_size = 0; file_addr = 0; if (m_fd < 0) { return false; } mt_com.mt_op = MTREW; mt_com.mt_count = 1; /* * If we get an I/O error on rewind, it is probably because * the drive is actually busy. We loop for (about 5 minutes) * retrying every 5 seconds. */ for (i = max_rewind_wait; ; i -= 5) { if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) { berrno be; clrerror(mt_com.mt_op); if (i == max_rewind_wait) { Dmsg1(200, "Rewind error, %s. retrying ...\n", be.bstrerror()); } /* * This is a gross hack, because if the user has the * device mounted (i.e. open), then uses mtx to load * a tape, the current open file descriptor is invalid. * So, we close the drive and re-open it. */ if (first && dcr) { int oo_mode = open_mode; d_close(m_fd); clear_opened(); open(dcr, oo_mode); if (m_fd < 0) { return false; } first = false; continue; } #ifdef HAVE_SUN_OS if (dev_errno == EIO) { Mmsg1(errmsg, _("No tape loaded or drive offline on %s.\n"), prt_name); return false; } #else if (dev_errno == EIO && i > 0) { Dmsg0(200, "Sleeping 5 seconds.\n"); bmicrosleep(5, 0); continue; } #endif Mmsg2(errmsg, _("Rewind error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); return false; } break; } return true; }