* to carry out operations without worrying about who
* set what lock (i.e. race conditions).
*
- * Note, this is the device dependent code, and my have
+ * Note, this is the device dependent code, and may have
* to be modified for each system, but is meant to
* be as "generic" as possible.
*
DCR *dcr = NULL;
DEVICE *dev;
-
+
/* If no device type specified, try to guess */
if (!device->dev_type) {
/* Check that device is available */
dev = (DEVICE *)malloc(sizeof(DEVICE));
memset(dev, 0, sizeof(DEVICE));
- dev->state = ST_MALLOC;
+ dev->Slot = -1; /* unknown */
/* Copy user supplied device parameters from Resource */
dev->dev_name = get_memory(strlen(device->device_name)+1);
dev->prt_name = get_memory(strlen(device->device_name) + strlen(device->hdr.name) + 20);
/* We edit "Resource-name" (physical-name) */
Mmsg(dev->prt_name, "\"%s\" (%s)", device->hdr.name, device->device_name);
+ Dmsg1(400, "Allocate dev=%s\n", dev->print_name());
dev->capabilities = device->cap_bits;
dev->min_block_size = device->min_block_size;
dev->max_block_size = device->max_block_size;
if (dev->vol_poll_interval && dev->vol_poll_interval < 60) {
dev->vol_poll_interval = 60;
}
+ /* Link the dev and device structures together */
dev->device = device;
+ device->dev = dev;
if (dev->is_fifo()) {
dev->capabilities |= CAP_STREAM; /* set stream device */
if (openmode == omode) {
return fd;
} else {
- ::close(fd); /* use system close so correct mode will be used on open */
- clear_opened();
- Dmsg0(100, "Close fd for mode change.\n");
- preserve = state & (ST_LABEL|ST_APPEND|ST_READ);
+ if (is_tape()) {
+ tape_close(fd);
+ } else {
+ ::close(fd);
+ }
+ clear_opened();
+ Dmsg0(100, "Close fd for mode change.\n");
+ preserve = state & (ST_LABEL|ST_APPEND|ST_READ);
}
}
if (dcr) {
Dmsg4(29, "open dev: type=%d dev_name=%s vol=%s mode=%s\n", dev_type,
print_name(), VolCatInfo.VolCatName, mode_to_str(omode));
state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
+ Slot = -1; /* unknown slot */
label_type = B_BACULA_LABEL;
if (is_tape() || is_fifo()) {
open_tape_device(dcr, omode);
open_file_device(dcr, omode);
}
state |= preserve; /* reset any important state info */
- if (preserve) {
- Dmsg1(000, "preserve=0x%x\n", preserve);
- }
+ Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, fd);
return fd;
}
int nonblocking = O_NONBLOCK;
Dmsg0(29, "open dev: device is tape\n");
- if (is_tape() && is_autochanger()) {
- get_autochanger_loaded_slot(dcr);
- }
+ get_autochanger_loaded_slot(dcr);
set_mode(omode);
timeout = max_open_wait;
Dmsg3(100, "Try open %s mode=%s nonblocking=%d\n", print_name(),
mode_to_str(omode), nonblocking);
/* Use system open() */
+
+#if defined(HAVE_WIN32)
+ if ((fd = tape_open(dev_name, mode)) < 0) {
+ berrno be;
+ dev_errno = errno;
+
+ Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"),
+ print_name(), be.strerror(dev_errno));
+ Jmsg0(dcr->jcr, M_FATAL, 0, errmsg);
+ }
+#else
while ((fd = ::open(dev_name, mode+nonblocking)) < 0) {
berrno be;
dev_errno = errno;
Jmsg0(dcr->jcr, M_FATAL, 0, errmsg);
break;
}
+#endif
if (fd >= 0) {
openmode = omode; /* save open mode */
{
POOL_MEM archive_name(PM_FNAME);
+ get_autochanger_loaded_slot(dcr);
+
/*
* Handle opening of File Archive (not a tape)
*/
- if (VolCatInfo.VolCatName[0] == 0) {
- Mmsg(errmsg, _("Could not open file device %s. No Volume name given.\n"),
- print_name());
- clear_opened();
- return;
- }
-
pm_strcpy(archive_name, dev_name);
- if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
- pm_strcat(archive_name, "/");
+ /*
+ * If this is a virtual autochanger (i.e. changer_res != NULL)
+ * we simply use the deviced name, assuming it has been
+ * appropriately setup by the "autochanger".
+ */
+ if (!device->changer_res) {
+ if (VolCatInfo.VolCatName[0] == 0) {
+ Mmsg(errmsg, _("Could not open file device %s. No Volume name given.\n"),
+ print_name());
+ clear_opened();
+ return;
+ }
+
+ if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
+ pm_strcat(archive_name, "/");
+ }
+ pm_strcat(archive_name, VolCatInfo.VolCatName);
}
- pm_strcat(archive_name, VolCatInfo.VolCatName);
mount(1); /* do mount if required */
update_pos_dev(this); /* update position */
}
Dmsg4(29, "open dev: disk fd=%d opened, part=%d/%d, part_size=%u\n",
- fd, part, num_parts, part_size);
+ fd, part, num_dvd_parts, part_size);
}
/*
Dmsg3(29, "Enter: open_dvd_dev: %s dev=%s mode=%s\n", is_dvd()?"DVD":"disk",
archive_name.c_str(), mode_to_str(omode));
+ /*
+ * For a DVD we must alway pull the state info from dcr->VolCatInfo
+ * This is a bit ugly, but is necessary because we need to open/close/re-open
+ * the dvd file in order to properly mount/unmount and access the
+ * DVD. So we store the state of the DVD as far as is known in the
+ * catalog in dcr->VolCatInfo, and thus we refresh the dev->VolCatInfo
+ * copy here, when opening.
+ */
+ memcpy(&VolCatInfo, &dcr->VolCatInfo, sizeof(VolCatInfo));
+ Dmsg1(100, "Volume=%s\n", VolCatInfo.VolCatName);
+
if (VolCatInfo.VolCatName[0] == 0) {
Dmsg1(10, "Could not open file device %s. No Volume name given.\n",
print_name());
}
if (part == 0) {
+ Dmsg0(100, "Set part=1\n");
+ part = 1; /* count from 1 */
file_size = 0;
}
part_size = 0;
-
- Dmsg2(99, "open_dvd_device: num_parts=%d, VolCatInfo.VolCatParts=%d\n",
- dcr->dev->num_parts, dcr->VolCatInfo.VolCatParts);
- if (dcr->dev->num_parts < dcr->VolCatInfo.VolCatParts) {
- Dmsg2(99, "open_dvd_device: num_parts updated to %d (was %d)\n",
- dcr->VolCatInfo.VolCatParts, dcr->dev->num_parts);
- dcr->dev->num_parts = dcr->VolCatInfo.VolCatParts;
+ if (num_dvd_parts != VolCatInfo.VolCatParts) {
+ num_dvd_parts = VolCatInfo.VolCatParts;
}
+ // Clear any previous truncated_dvd status - we will recalculate it here
+ truncated_dvd = false;
+ Dmsg3(99, "open_dvd_device: part=%d num_dvd_parts=%d, VolCatInfo.VolCatParts=%d\n",
+ part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
+
if (mount_dvd(this, 1)) {
- if ((num_parts == 0) && (!truncating)) {
- /* If we can mount the device, and we are not truncating the DVD, we usually want to abort. */
- /* There is one exception, if there is only one 0-sized file on the DVD, with the right volume name,
- * we continue (it's the method used by truncate_dvd to truncate a volume). */
+ Dmsg0(99, "DVD device mounted.\n");
+ if (num_dvd_parts == 0 && !truncating) {
+ /*
+ * If we can mount the device, and we are not truncating the DVD,
+ * we usually want to abort. There is one exception, if there is
+ * only one 0-sized file on the DVD, with the right volume name,
+ * we continue (it's the method used by truncate_dvd to truncate a volume).
+ */
if (!check_can_write_on_non_blank_dvd(dcr)) {
Mmsg(errmsg, _("The media in the device %s is not empty, please blank it before writing anything to it.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
clear_opened();
return;
}
+ truncated_dvd = true;
}
} else {
+ Dmsg0(99, "DVD device mount failed.\n");
/* We cannot mount the device */
- if (num_parts == 0) {
+ if (num_dvd_parts == 0) {
/* Run free space, check there is a media. */
- update_free_space_dev(this);
- if (have_media()) {
- Dmsg1(29, "Could not mount device %s, this is not a problem (num_parts == 0), and have media.\n", print_name());
+ if (!update_free_space_dev(this)) {
+ Emsg0(M_FATAL, 0, errmsg);
+ clear_opened();
+ return;
}
- else {
+ if (have_media()) {
+ Dmsg1(29, "Could not mount device %s, this is not a problem (num_dvd_parts == 0), and have media.\n", print_name());
+ } else {
Mmsg(errmsg, _("There is no valid media in the device %s.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
clear_opened();
return;
}
- }
- else {
+ } else {
Mmsg(errmsg, _("Could not mount device %s.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
clear_opened();
}
}
- Dmsg6(29, "open dev: %s dev=%s mode=%s part=%d npart=%d volcatnparts=%d\n",
- is_dvd()?"DVD":"disk", archive_name.c_str(), mode_to_str(omode),
- part, num_parts, dcr->VolCatInfo.VolCatParts);
+ Dmsg5(29, "open dev: DVD dev=%s mode=%s part=%d npart=%d volcatnparts=%d\n",
+ archive_name.c_str(), mode_to_str(omode),
+ part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
openmode = omode;
Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
* If we are not trying to access the last part, set mode to
* OPEN_READ_ONLY as writing would be an error.
*/
- if (part < num_parts) {
+ Dmsg2(29, "open DVD part=%d num_dvd_parts=%d\n", part, num_dvd_parts);
+ if (part <= num_dvd_parts) {
omode = OPEN_READ_ONLY;
make_mounted_dvd_filename(this, archive_name);
- }
- else {
+ } else {
+ omode = OPEN_READ_WRITE;
make_spooled_dvd_filename(this, archive_name);
}
set_mode(omode);
berrno be;
Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(),
be.strerror());
+ // Should this be set if we try the create/open below
dev_errno = EIO; /* Interpreted as no device present by acquire.c:acquire_device_for_read(). */
Dmsg1(29, "open failed: %s", errmsg);
- if ((omode == OPEN_READ_ONLY) && (part == num_parts)) {
- /* If the last part (on spool), doesn't exists when reading, create it and read from it
- * (it will report immediately an EOF):
+ /* Previous open failed. See if we can recover */
+ if ((omode == OPEN_READ_ONLY || omode == OPEN_READ_WRITE) &&
+ (part > num_dvd_parts)) {
+ /* If the last part (on spool), doesn't exist when accessing,
+ * create it. In read/write mode a write will be allowed (higher
+ * level software thinks that we are extending a pre-existing
+ * media. Reads for READ_ONLY will report immediately an EOF
* Sometimes it is better to finish with an EOF than with an error. */
- set_mode(OPEN_READ_WRITE);
+ Dmsg1(29, "Creating last part on spool: %s\n", archive_name.c_str());
+ omode = CREATE_READ_WRITE;
+ set_mode(CREATE_READ_WRITE);
fd = ::open(archive_name.c_str(), mode, 0640);
- set_mode(OPEN_READ_ONLY);
+ set_mode(omode);
}
-
- /* We don't need it. Only the last part is on spool */
- /*if (omode == OPEN_READ_ONLY) {
- make_spooled_dvd_filename(this, archive_name);
- fd = ::open(archive_name.c_str(), mode, 0640); // try on spool
- }*/
}
Dmsg1(100, "after open fd=%d\n", fd);
if (fd >= 0) {
+ if (omode == OPEN_READ_WRITE || omode == CREATE_READ_WRITE) {
+ set_append();
+ }
/* Get size of file */
if (fstat(fd, &filestat) < 0) {
berrno be;
part_size = filestat.st_size;
dev_errno = 0;
update_pos_dev(this); /* update position */
-
- /* NB: It seems this code is wrong... part number is incremented in open_next_part, not here */
-
- /* Check if just created Volume part */
-/* if (omode == OPEN_READ_WRITE && (part == 0 || part_size == 0)) {
- part++;
- num_parts = part;
- VolCatInfo.VolCatParts = num_parts;
- } else {
- if (part == 0) { // we must have opened the first part
- part++;
- }
- }*/
}
}
}
unsigned int i;
bool first = true;
- Dmsg3(29, "rewind res=%d fd=%d %s\n", reserved_device, fd, print_name());
+ Dmsg3(400, "rewind res=%d fd=%d %s\n", reserved_device, fd, print_name());
+ state &= ~(ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
+ block_num = file = 0;
+ file_size = 0;
+ file_addr = 0;
if (fd < 0) {
if (!is_dvd()) { /* In case of major error, the fd is not open on DVD, so we don't want to abort. */
dev_errno = EBADF;
}
return false;
}
- state &= ~(ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
- block_num = file = 0;
- file_size = 0;
- file_addr = 0;
if (is_tape()) {
mt_com.mt_op = MTREW;
mt_com.mt_count = 1;
* retrying every 5 seconds.
*/
for (i=max_rewind_wait; ; i -= 5) {
- if (ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ if (tape_ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
berrno be;
- clrerror_dev(this, MTREW);
+ clrerror(MTREW);
if (i == max_rewind_wait) {
Dmsg1(200, "Rewind error, %s. retrying ...\n", be.strerror());
}
*/
if (first && dcr) {
int open_mode = openmode;
- ::close(fd);
+ tape_close(fd);
clear_opened();
open(dcr, open_mode);
if (fd < 0) {
first = false;
continue;
}
+#ifdef HAVE_SUN_OS
+ if (dev_errno == EIO) {
+ Mmsg1(errmsg, _("No tape loaded or drive offline on %s.\n"), print_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"),
print_name(), be.strerror());
return false;
}
break;
}
- } else if (is_file()) {
+ } else if (is_file() || is_dvd()) {
if (lseek_dev(this, (off_t)0, SEEK_SET) < 0) {
berrno be;
dev_errno = errno;
if (at_eot()) {
return true;
}
- state &= ~(ST_EOF); /* remove EOF flags */
+ clear_eof(); /* remove EOF flag */
block_num = file = 0;
file_size = 0;
file_addr = 0;
// Dmsg1(100, "====== Seek to %lld\n", pos);
if (pos >= 0) {
update_pos_dev(this);
- state |= ST_EOT;
+ set_eot();
return true;
}
dev_errno = errno;
mt_com.mt_count = 1;
}
- if (ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ if (tape_ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
berrno be;
- clrerror_dev(this, mt_com.mt_op);
+ clrerror(mt_com.mt_op);
Dmsg1(50, "ioctl error: %s\n", be.strerror());
update_pos_dev(this);
Mmsg2(errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"),
if (!dev_get_os_pos(this, &mt_stat)) {
berrno be;
- clrerror_dev(this, -1);
+ clrerror(-1);
Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
print_name(), be.strerror());
return false;
ok = false;
} else {
dev->file_addr = pos;
+ dev->block_num = (uint32_t)pos;
+ dev->file = (uint32_t)(pos >> 32);
}
}
return ok;
stat |= BMT_TAPE;
Pmsg0(-20,_(" Bacula status:"));
Pmsg2(-20,_(" file=%d block=%d\n"), dev->file, dev->block_num);
- if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
+ if (tape_ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
berrno be;
dev->dev_errno = errno;
Mmsg2(dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
stat |= BMT_IM_REP_EN;
Pmsg0(-20, " IM_REP_EN");
}
+#elif defined(HAVE_WIN32)
+ if (GMT_EOF(mt_stat.mt_gstat)) {
+ stat |= BMT_EOF;
+ Pmsg0(-20, " EOF");
+ }
+ if (GMT_BOT(mt_stat.mt_gstat)) {
+ stat |= BMT_BOT;
+ Pmsg0(-20, " BOT");
+ }
+ if (GMT_EOT(mt_stat.mt_gstat)) {
+ stat |= BMT_EOT;
+ Pmsg0(-20, " EOT");
+ }
+ if (GMT_EOD(mt_stat.mt_gstat)) {
+ stat |= BMT_EOD;
+ Pmsg0(-20, " EOD");
+ }
+ if (GMT_WR_PROT(mt_stat.mt_gstat)) {
+ stat |= BMT_WR_PROT;
+ Pmsg0(-20, " WR_PROT");
+ }
+ if (GMT_ONLINE(mt_stat.mt_gstat)) {
+ stat |= BMT_ONLINE;
+ Pmsg0(-20, " ONLINE");
+ }
+ if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
+ stat |= BMT_DR_OPEN;
+ Pmsg0(-20, " DR_OPEN");
+ }
+ if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
+ stat |= BMT_IM_REP_EN;
+ Pmsg0(-20, " IM_REP_EN");
+ }
+
#endif /* !SunOS && !OSF */
if (dev->has_cap(CAP_MTIOCGET)) {
Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno);
dev->file_addr = 0;
mt_com.mt_op = MTLOAD;
mt_com.mt_count = 1;
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
berrno be;
dev->dev_errno = errno;
Mmsg2(dev->errmsg, _("ioctl MTLOAD error on %s. ERR=%s.\n"),
block_num = file = 0;
file_size = 0;
file_addr = 0;
- part = 0;
#ifdef MTUNLOCK
mt_com.mt_op = MTUNLOCK;
mt_com.mt_count = 1;
- ioctl(fd, MTIOCTOP, (char *)&mt_com);
+ tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
#endif
mt_com.mt_op = MTOFFL;
mt_com.mt_count = 1;
- if (ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ if (tape_ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
berrno be;
dev_errno = errno;
Mmsg2(errmsg, _("ioctl MTOFFL error on %s. ERR=%s.\n"),
* such as backspacing after writing and EOF. If it is not
* done, all future references to the drive get and I/O error.
*/
- clrerror_dev(this, MTREW);
+ clrerror(MTREW);
return rewind(NULL);
}
}
if (has_cap(CAP_FSF) && has_cap(CAP_MTIOCGET) && has_cap(CAP_FASTFSF)) {
mt_com.mt_op = MTFSF;
mt_com.mt_count = num;
- stat = ioctl(fd, MTIOCTOP, (char *)&mt_com);
+ stat = tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
if (stat < 0 || !dev_get_os_pos(this, &mt_stat)) {
berrno be;
set_eot();
Dmsg0(200, "Set ST_EOT\n");
- clrerror_dev(this, MTFSF);
+ clrerror(MTFSF);
Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
print_name(), be.strerror());
Dmsg1(200, "%s", errmsg);
mt_com.mt_count = 1;
while (num-- && !at_eot()) {
Dmsg0(100, "Doing read before fsf\n");
- if ((stat = read(fd, (char *)rbuf, rbuf_len)) < 0) {
+ if ((stat = tape_read(fd, (char *)rbuf, rbuf_len)) < 0) {
if (errno == ENOMEM) { /* tape record exceeds buf len */
stat = rbuf_len; /* This is OK */
/*
} else {
berrno be;
set_eot();
- clrerror_dev(this, -1);
+ clrerror(-1);
Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev_errno,
be.strerror());
Mmsg2(errmsg, _("read error on %s. ERR=%s.\n"),
}
Dmsg0(100, "Doing MTFSF\n");
- stat = ioctl(fd, MTIOCTOP, (char *)&mt_com);
+ stat = tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
if (stat < 0) { /* error => EOT */
berrno be;
set_eot();
Dmsg0(100, "Set ST_EOT\n");
- clrerror_dev(this, MTFSF);
+ clrerror(MTFSF);
Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
print_name(), be.strerror());
Dmsg0(100, "Got < 0 for MTFSF\n");
}
update_pos_dev(this);
Dmsg1(200, "Return %d from FSF\n", stat);
- if (at_eof())
+ if (at_eof()) {
Dmsg0(200, "ST_EOF set on exit FSF\n");
- if (at_eot())
+ }
+ if (at_eot()) {
Dmsg0(200, "ST_EOT set on exit FSF\n");
+ }
Dmsg1(200, "Return from FSF file=%d\n", file);
return stat == 0;
}
return false;
}
Dmsg0(29, "bsf\n");
- state &= ~(ST_EOT|ST_EOF);
+ clear_eot();
+ clear_eof();
file -= num;
file_addr = 0;
file_size = 0;
mt_com.mt_op = MTBSF;
mt_com.mt_count = num;
- stat = ioctl(fd, MTIOCTOP, (char *)&mt_com);
+ stat = tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
if (stat < 0) {
berrno be;
- clrerror_dev(this, MTBSF);
+ clrerror(MTBSF);
Mmsg2(errmsg, _("ioctl MTBSF error on %s. ERR=%s.\n"),
print_name(), be.strerror());
}
Dmsg1(29, "fsr %d\n", num);
mt_com.mt_op = MTFSR;
mt_com.mt_count = num;
- stat = ioctl(fd, MTIOCTOP, (char *)&mt_com);
+ stat = tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
if (stat == 0) {
clear_eof();
block_num += num;
} else {
berrno be;
struct mtget mt_stat;
- clrerror_dev(this, MTFSR);
+ clrerror(MTFSR);
Dmsg1(100, "FSF fail: ERR=%s\n", be.strerror());
if (dev_get_os_pos(this, &mt_stat)) {
Dmsg4(100, "Adjust from %d:%d to %d:%d\n", file,
* Returns: false on failure
* true on success
*/
-bool
-bsr_dev(DEVICE *dev, int num)
+bool DEVICE::bsr(int num)
{
struct mtop mt_com;
int stat;
- if (dev->fd < 0) {
- dev->dev_errno = EBADF;
- Mmsg0(dev->errmsg, _("Bad call to bsr_dev. Device not open\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
+ if (fd < 0) {
+ dev_errno = EBADF;
+ Mmsg0(errmsg, _("Bad call to bsr_dev. Device not open\n"));
+ Emsg0(M_FATAL, 0, errmsg);
return false;
}
- if (!dev->is_tape()) {
+ if (!is_tape()) {
return false;
}
- if (!dev->has_cap(CAP_BSR)) {
- Mmsg1(dev->errmsg, _("ioctl MTBSR not permitted on %s.\n"), dev->print_name());
+ if (!has_cap(CAP_BSR)) {
+ Mmsg1(errmsg, _("ioctl MTBSR not permitted on %s.\n"), print_name());
return false;
}
Dmsg0(29, "bsr_dev\n");
- dev->block_num -= num;
- dev->state &= ~(ST_EOF|ST_EOT|ST_EOF);
+ block_num -= num;
+ clear_eof();
+ clear_eot();
mt_com.mt_op = MTBSR;
mt_com.mt_count = num;
- stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+ stat = tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
if (stat < 0) {
berrno be;
- clrerror_dev(dev, MTBSR);
- Mmsg2(dev->errmsg, _("ioctl MTBSR error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ clrerror(MTBSR);
+ Mmsg2(errmsg, _("ioctl MTBSR error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
}
- update_pos_dev(dev);
+ update_pos_dev(this);
return stat == 0;
}
* Returns: false on failure
* true on success
*/
-bool
-reposition_dev(DEVICE *dev, uint32_t file, uint32_t block)
+bool DEVICE::reposition(uint32_t rfile, uint32_t rblock)
{
- if (dev->fd < 0) {
- dev->dev_errno = EBADF;
- Mmsg0(dev->errmsg, _("Bad call to reposition_dev. Device not open\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
+ if (fd < 0) {
+ dev_errno = EBADF;
+ Mmsg0(errmsg, _("Bad call to reposition. Device not open\n"));
+ Emsg0(M_FATAL, 0, errmsg);
return false;
}
- if (!dev->is_tape()) {
- off_t pos = (((off_t)file)<<32) + (off_t)block;
+ if (!is_tape()) {
+ off_t pos = (((off_t)rfile)<<32) + (off_t)rblock;
Dmsg1(100, "===== lseek_dev to %d\n", (int)pos);
- if (lseek_dev(dev, pos, SEEK_SET) == (off_t)-1) {
+ if (lseek_dev(this, pos, SEEK_SET) == (off_t)-1) {
berrno be;
- dev->dev_errno = errno;
- Mmsg2(dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ dev_errno = errno;
+ Mmsg2(errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
return false;
}
- dev->file = file;
- dev->block_num = block;
- dev->file_addr = pos;
+ file = rfile;
+ block_num = rblock;
+ file_addr = pos;
return true;
}
- Dmsg4(100, "reposition_dev from %u:%u to %u:%u\n",
- dev->file, dev->block_num, file, block);
- if (file < dev->file) {
+ Dmsg4(100, "reposition from %u:%u to %u:%u\n",
+ file, block_num, rfile, rblock);
+ if (rfile < file) {
Dmsg0(100, "Rewind\n");
- if (!dev->rewind(NULL)) {
+ if (!rewind(NULL)) {
return false;
}
}
- if (file > dev->file) {
- Dmsg1(100, "fsf %d\n", file-dev->file);
- if (!dev->fsf(file-dev->file)) {
- Dmsg1(100, "fsf failed! ERR=%s\n", strerror_dev(dev));
+ if (rfile > file) {
+ Dmsg1(100, "fsf %d\n", rfile-file);
+ if (!fsf(rfile-file)) {
+ Dmsg1(100, "fsf failed! ERR=%s\n", bstrerror());
return false;
}
- Dmsg2(100, "wanted_file=%d at_file=%d\n", file, dev->file);
+ Dmsg2(100, "wanted_file=%d at_file=%d\n", rfile, file);
}
- if (block < dev->block_num) {
- Dmsg2(100, "wanted_blk=%d at_blk=%d\n", block, dev->block_num);
+ if (rblock < block_num) {
+ Dmsg2(100, "wanted_blk=%d at_blk=%d\n", rblock, block_num);
Dmsg0(100, "bsf 1\n");
- dev->bsf(1);
+ bsf(1);
Dmsg0(100, "fsf_dev 1\n");
- dev->fsf(1);
- Dmsg2(100, "wanted_blk=%d at_blk=%d\n", block, dev->block_num);
+ fsf(1);
+ Dmsg2(100, "wanted_blk=%d at_blk=%d\n", rblock, block_num);
}
- if (dev->has_cap(CAP_POSITIONBLOCKS) && block > dev->block_num) {
+ if (has_cap(CAP_POSITIONBLOCKS) && rblock > block_num) {
/* Ignore errors as Bacula can read to the correct block */
- Dmsg1(100, "fsr %d\n", block-dev->block_num);
- return dev->fsr(block-dev->block_num);
+ Dmsg1(100, "fsr %d\n", rblock-block_num);
+ return fsr(rblock-block_num);
}
return true;
}
/*
* Write an end of file on the device
- * Returns: 0 on success
- * non-zero on failure
+ * Returns: true on success
+ * false on failure
*/
-int
-weof_dev(DEVICE *dev, int num)
+bool DEVICE::weof(int num)
{
struct mtop mt_com;
int stat;
- Dmsg0(29, "weof_dev\n");
+ Dmsg0(129, "weof_dev\n");
- if (dev->fd < 0) {
- dev->dev_errno = EBADF;
- Mmsg0(dev->errmsg, _("Bad call to weof_dev. Device not open\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
- return -1;
+ if (fd < 0) {
+ dev_errno = EBADF;
+ Mmsg0(errmsg, _("Bad call to weof_dev. Device not open\n"));
+ Emsg0(M_FATAL, 0, errmsg);
+ return false;
}
- dev->file_size = 0;
+ file_size = 0;
- if (!dev->is_tape()) {
- return 0;
+ if (!is_tape()) {
+ return true;
}
- if (!dev->can_append()) {
- Mmsg0(dev->errmsg, _("Attempt to WEOF on non-appendable Volume\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
- return -1;
+ if (!can_append()) {
+ Mmsg0(errmsg, _("Attempt to WEOF on non-appendable Volume\n"));
+ Emsg0(M_FATAL, 0, errmsg);
+ return false;
}
- dev->state &= ~(ST_EOT | ST_EOF); /* remove EOF/EOT flags */
+ clear_eof();
+ clear_eot();
mt_com.mt_op = MTWEOF;
mt_com.mt_count = num;
- stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+ stat = tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
if (stat == 0) {
- dev->block_num = 0;
- dev->file += num;
- dev->file_addr = 0;
+ block_num = 0;
+ file += num;
+ file_addr = 0;
} else {
berrno be;
- clrerror_dev(dev, MTWEOF);
+ clrerror(MTWEOF);
if (stat == -1) {
- Mmsg2(dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ Mmsg2(errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
}
}
- return stat;
-}
-
-/*
- * Return string message with last error in English
- * Be careful not to call this routine from within dev.c
- * while editing an Mmsg() or you will end up in a recursive
- * loop creating a Segmentation Violation.
- */
-char *
-strerror_dev(DEVICE *dev)
-{
- return dev->errmsg;
+ return stat == 0;
}
* If implemented in system, clear the tape
* error status.
*/
-void
-clrerror_dev(DEVICE *dev, int func)
+void DEVICE::clrerror(int func)
{
const char *msg = NULL;
struct mtget mt_stat;
char buf[100];
- dev->dev_errno = errno; /* save errno */
+ dev_errno = errno; /* save errno */
if (errno == EIO) {
- dev->VolCatInfo.VolCatErrors++;
+ VolCatInfo.VolCatErrors++;
}
- if (!dev->is_tape()) {
+ if (!is_tape()) {
return;
}
if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
switch (func) {
case -1:
- Emsg0(M_ABORT, 0, _("Got ENOTTY on read/write!\n"));
- break;
+ break; /* ignore message printed later */
case MTWEOF:
msg = "WTWEOF";
- dev->capabilities &= ~CAP_EOF; /* turn off feature */
+ capabilities &= ~CAP_EOF; /* turn off feature */
break;
#ifdef MTEOM
case MTEOM:
msg = "WTEOM";
- dev->capabilities &= ~CAP_EOM; /* turn off feature */
+ capabilities &= ~CAP_EOM; /* turn off feature */
break;
#endif
case MTFSF:
msg = "MTFSF";
- dev->capabilities &= ~CAP_FSF; /* turn off feature */
+ capabilities &= ~CAP_FSF; /* turn off feature */
break;
case MTBSF:
msg = "MTBSF";
- dev->capabilities &= ~CAP_BSF; /* turn off feature */
+ capabilities &= ~CAP_BSF; /* turn off feature */
break;
case MTFSR:
msg = "MTFSR";
- dev->capabilities &= ~CAP_FSR; /* turn off feature */
+ capabilities &= ~CAP_FSR; /* turn off feature */
break;
case MTBSR:
msg = "MTBSR";
- dev->capabilities &= ~CAP_BSR; /* turn off feature */
+ capabilities &= ~CAP_BSR; /* turn off feature */
break;
case MTREW:
msg = "MTREW";
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->dev_errno = ENOSYS;
- Mmsg1(dev->errmsg, _("I/O function \"%s\" not supported on this device.\n"), msg);
- Emsg0(M_ERROR, 0, dev->errmsg);
+ 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 */
- ioctl(dev->fd, MTIOCGET, (char *)&mt_stat);
+ tape_ioctl(fd, MTIOCGET, (char *)&mt_stat);
/* Found on Linux */
#ifdef MTIOCLRERR
mt_com.mt_op = MTIOCLRERR;
mt_com.mt_count = 1;
/* Clear any error condition on the tape */
- ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+ tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
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->dev_errno,
- strerror(dev->dev_errno));
- ioctl(dev->fd, MTIOCERRSTAT, (char *)&mt_errstat);
+ Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev_errno,
+ be.strerror(dev_errno));
+ tape_ioctl(fd, MTIOCERRSTAT, (char *)&mt_errstat);
}
#endif
mt_com.mt_op = MTCSE;
mt_com.mt_count = 1;
/* Clear any error condition on the tape */
- ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+ tape_ioctl(fd, MTIOCTOP, (char *)&mt_com);
Dmsg0(200, "Did MTCSE\n");
}
#endif
}
-/*
- * Flush buffer contents
- * No longer used.
- */
-int flush_dev(DEVICE *dev)
-{
- return 1;
-}
-
/*
* Close the device
*/
offline();
}
if (fd >= 0) {
- ::close(fd);
+ if (is_tape()) {
+ tape_close(fd);
+ } else {
+ ::close(fd);
+ }
} else {
+ Dmsg2(100, "device %s already closed vol=%s\n", print_name(),
+ VolHdr.VolumeName);
return; /* already closed */
}
}
/* Remove the last part file if it is empty */
- if (num_parts > 0) {
+ if (num_dvd_parts > 0) {
struct stat statp;
+ int part_save = part;
POOL_MEM archive_name(PM_FNAME);
- part = num_parts;
- Dmsg1(100, "Call make_dvd_filename. Vol=%s\n", VolCatInfo.VolCatName);
+ int status;
+
+ part = num_dvd_parts;
make_spooled_dvd_filename(this, archive_name);
/* Check that the part file is empty */
- if ((stat(archive_name.c_str(), &statp) == 0) && (statp.st_size == 0)) {
+ status = stat(archive_name.c_str(), &statp);
+ if (status == 0 && statp.st_size == 0) {
+ Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
+ part, num_dvd_parts, VolCatInfo.VolCatName);
Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
unlink(archive_name.c_str());
- }
+ set_part_spooled(false); /* no spooled part left */
+ } else if (status < 0) {
+ set_part_spooled(false); /* spool doesn't exit */
+ }
+ part = part_save; /* restore part number */
}
/* Clean up device packet so it can be reused */
file = block_num = 0;
file_size = 0;
file_addr = 0;
- part = 0;
- num_parts = 0;
- part_size = 0;
- part_start = 0;
EndFile = EndBlock = 0;
- memset(&VolCatInfo, 0, sizeof(VolCatInfo));
+ Slot = -1; /* unknown slot */
free_volume(this);
+ memset(&VolCatInfo, 0, sizeof(VolCatInfo));
memset(&VolHdr, 0, sizeof(VolHdr));
if (tid) {
stop_thread_timer(tid);
*/
bool DEVICE::mount(int timeout)
{
- Dmsg0(90, "Enter mount\n");
+ Dmsg0(190, "Enter mount\n");
if (is_mounted()) {
return true;
} else if (requires_mount()) {
edit_mount_codes(ocmd, icmd);
- Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
+ Dmsg2(000, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
if (dotimeout) {
/* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
}
results = get_memory(2000);
results[0] = 0;
+
/* If busy retry each second */
+ Dmsg1(20, "do_mount run_prog=%s\n", ocmd.c_str());
while ((status = run_program_full_output(ocmd.c_str(),
max_open_wait/2, results)) != 0) {
/* Doesn't work with internationalisation (This is not a problem) */
str = dev_name;
break;
case 'e':
- if (num_parts == 0) {
- str = "1";
+ if (num_dvd_parts == 0) {
+ if (truncating || truncated_dvd) {
+ str = "2";
+ } else {
+ str = "1";
+ }
} else {
str = "0";
}
/*
* Free memory allocated for the device
*/
-void
-term_dev(DEVICE *dev)
+void DEVICE::term(void)
{
- if (!dev) {
- dev->dev_errno = EBADF;
- Mmsg0(dev->errmsg, _("Bad call to term_dev. Device not open\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
- return;
- }
- Dmsg1(29, "term_dev: %s\n", dev->print_name());
- dev->close();
- if (dev->dev_name) {
- free_memory(dev->dev_name);
- dev->dev_name = NULL;
- }
- if (dev->prt_name) {
- free_memory(dev->prt_name);
- dev->prt_name = NULL;
- }
- if (dev->errmsg) {
- free_pool_memory(dev->errmsg);
- dev->errmsg = NULL;
- }
- pthread_mutex_destroy(&dev->mutex);
- pthread_cond_destroy(&dev->wait);
- pthread_cond_destroy(&dev->wait_next_vol);
- pthread_mutex_destroy(&dev->spool_mutex);
- rwl_destroy(&dev->lock);
- if (dev->attached_dcrs) {
- delete dev->attached_dcrs;
- dev->attached_dcrs = NULL;
- }
- if (dev->state & ST_MALLOC) {
- free((char *)dev);
- }
+ Dmsg1(900, "term dev: %s\n", print_name());
+ close();
+ if (dev_name) {
+ free_memory(dev_name);
+ dev_name = NULL;
+ }
+ if (prt_name) {
+ free_memory(prt_name);
+ prt_name = NULL;
+ }
+ if (errmsg) {
+ free_pool_memory(errmsg);
+ errmsg = NULL;
+ }
+ pthread_mutex_destroy(&mutex);
+ pthread_cond_destroy(&wait);
+ pthread_cond_destroy(&wait_next_vol);
+ pthread_mutex_destroy(&spool_mutex);
+ rwl_destroy(&lock);
+ if (attached_dcrs) {
+ delete attached_dcrs;
+ attached_dcrs = NULL;
+ }
+ if (device) {
+ device->dev = NULL;
+ }
+ free((char *)this);
}
/*
void set_os_device_parameters(DEVICE *dev)
{
-#ifdef HAVE_LINUX_OS
+#if defined(HAVE_LINUX_OS) || defined(HAVE_WIN32)
struct mtop mt_com;
if (dev->min_block_size == dev->max_block_size &&
dev->min_block_size == 0) { /* variable block mode */
mt_com.mt_op = MTSETBLK;
mt_com.mt_count = 0;
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
- clrerror_dev(dev, MTSETBLK);
+ if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ dev->clrerror(MTSETBLK);
}
mt_com.mt_op = MTSETDRVBUFFER;
mt_com.mt_count = MT_ST_CLEARBOOLEANS;
if (dev->has_cap(CAP_EOM)) {
mt_com.mt_count |= MT_ST_FAST_MTEOM;
}
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
- clrerror_dev(dev, MTSETBLK);
+ if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ dev->clrerror(MTSETBLK);
}
}
return;
dev->min_block_size == 0) { /* variable block mode */
mt_com.mt_op = MTSETBSIZ;
mt_com.mt_count = 0;
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
- clrerror_dev(dev, MTSETBSIZ);
+ if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ dev->clrerror(MTSETBSIZ);
}
/* Get notified at logical end of tape */
mt_com.mt_op = MTEWARN;
mt_com.mt_count = 1;
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
- clrerror_dev(dev, MTEWARN);
+ if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ dev->clrerror(MTEWARN);
}
}
return;
dev->min_block_size == 0) { /* variable block mode */
mt_com.mt_op = MTSETBSIZ;
mt_com.mt_count = 0;
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
- clrerror_dev(dev, MTSETBSIZ);
+ if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ dev->clrerror(MTSETBSIZ);
}
}
return;
dev->min_block_size == 0) { /* variable block mode */
mt_com.mt_op = MTSRSZ;
mt_com.mt_count = 0;
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
- clrerror_dev(dev, MTSRSZ);
+ if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ dev->clrerror(MTSRSZ);
}
}
return;
static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat)
{
return dev->has_cap(CAP_MTIOCGET) &&
- ioctl(dev->fd, MTIOCGET, (char *)mt_stat) == 0 &&
+ tape_ioctl(dev->fd, MTIOCGET, (char *)mt_stat) == 0 &&
mt_stat->mt_fileno >= 0;
}
static char *mode_to_str(int mode)
{
+ static char buf[100];
+ if (mode < 1 || mode > 4) {
+ bsnprintf(buf, sizeof(buf), "BAD mode=%d", mode);
+ return buf;
+ }
return modes[mode-1];
}