return fd;
} else {
::close(fd); /* use system close so correct mode will be used on open */
+ fd = -1;
+ Dmsg0(100, "Close fd for mode change.\n");
}
}
- if (dcr) {
- bstrncpy(VolCatInfo.VolCatName, dcr->VolumeName, sizeof(VolCatInfo.VolCatName));
- }
+ if (dcr) {
+ bstrncpy(VolCatInfo.VolCatName, dcr->VolumeName, sizeof(VolCatInfo.VolCatName));
+ }
Dmsg4(29, "open dev: tape=%d dev_name=%s vol=%s mode=%s\n", is_tape(),
print_name(), VolCatInfo.VolCatName, mode_to_str(omode));
state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
label_type = B_BACULA_LABEL;
if (is_tape() || is_fifo()) {
- open_tape_device(omode);
+ open_tape_device(dcr, omode);
} else if (is_dvd()) {
Dmsg1(100, "call open_dvd_device mode=%s\n", mode_to_str(omode));
open_dvd_device(dcr, omode);
}
}
-void DEVICE::open_tape_device(int omode)
+/*
+ * If the flage open_nowait is set, which is the case
+ * when the daemon is initially trying to open the device,
+ * we open it with O_NONBLOCK set and O_RONLY, which will
+ * allow us to open normal Linux tape drives with no tape
+ * in the drive without blocking. We then immediately
+ * set blocking status so that if we read from the device they
+ * will be normal blocking reads.
+ *
+ * If later, we want to write on the device, it will be freed and
+ * reopened, but hopefully there will be a tape in the drive so
+ * we will not block.
+ */
+void DEVICE::open_tape_device(DCR *dcr, int omode)
{
- int nonblocking = 0;;
+ int nonblocking = 0;
file_size = 0;
int timeout;
int ioerrcnt = 10;
Dmsg0(29, "open dev: device is tape\n");
+ if (is_tape() && is_autochanger()) {
+ get_autochanger_loaded_slot(dcr);
+ }
+
set_mode(omode);
timeout = max_open_wait;
errno = 0;
+#ifdef HAVE_LINUX_OS
if (open_nowait) {
/* Set wait counters to zero for no wait */
timeout = ioerrcnt = 0;
/* Open drive in non-block mode */
nonblocking = O_NONBLOCK;
}
+#endif
if (is_fifo() && timeout) {
/* Set open timer */
tid = start_thread_timer(pthread_self(), timeout);
}
/* If busy retry each second for max_open_wait seconds */
-open_again:
- Dmsg1(500, "Try open %s\n", print_name());
+ Dmsg3(100, "Try open %s mode=%s nonblocking=%d\n", print_name(),
+ mode_to_str(omode), nonblocking);
/* Use system open() */
- while ((fd = ::open(dev_name, mode, MODE_RW+nonblocking)) < 0) {
+ while ((fd = ::open(dev_name, mode+nonblocking, MODE_RW)) < 0) {
berrno be;
- Dmsg2(500, "Open error errno=%d ERR=%s\n", errno, be.strerror());
+ Dmsg2(100, "Open error errno=%d ERR=%s\n", errno, be.strerror());
if (errno == EINTR || errno == EAGAIN) {
- Dmsg0(500, "Continue open\n");
+ Dmsg0(100, "Continue open\n");
continue;
}
/* Busy wait for specified time (default = 5 mins) */
/* IO error (no volume) try 10 times every 6 seconds */
if (errno == EIO && ioerrcnt-- > 0) {
bmicrosleep(5, 0);
- Dmsg0(500, "Continue open\n");
+ Dmsg0(100, "Continue open\n");
continue;
}
dev_errno = errno;
stop_thread_timer(tid);
tid = 0;
}
- Emsg0(M_FATAL, 0, errmsg);
+ Jmsg0(dcr->jcr, M_FATAL, 0, errmsg);
break;
}
+
+ if (nonblocking) {
+ set_blocking();
+ }
+
if (fd >= 0) {
- /* If opened in non-block mode, close it an open it normally */
- if (nonblocking) {
- nonblocking = 0;
- ::close(fd); /* use system close() */
- goto open_again;
- }
openmode = omode; /* save open mode */
Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
dev_errno = 0;
use_count = 1;
update_pos_dev(this); /* update position */
set_os_device_parameters(this); /* do system dependent stuff */
- Dmsg0(500, "Open OK\n");
}
+
/* Stop any open() timer we started */
if (tid) {
stop_thread_timer(tid);
Dmsg1(29, "open dev: tape %d opened\n", fd);
}
+void DEVICE::set_blocking()
+{
+ int oflags;
+ /* Try to reset blocking */
+ if ((oflags = fcntl(fd, F_GETFL, 0)) < 0 ||
+ fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) < 0) {
+ berrno be;
+ ::close(fd); /* use system close() */
+ fd = ::open(dev_name, mode, MODE_RW);
+ Dmsg2(100, "fcntl error. ERR=%s. Close-reopen fd=%d\n", be.strerror(), fd);
+ }
+}
+
/*
* Open a file device
*/
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);
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);
+ unmount_dev(this, 1); /* Unmount the device, so the operator can change it. */
fd = -1;
return;
}
/* We cannot mount the device */
if (num_parts == 0) {
/* Run free space, check there is a media. */
- Dmsg1(29, "Could not mount device %s, this is not a problem (num_parts == 0).\n", print_name());
+ 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());
+ }
+ else {
+ Mmsg(errmsg, _("There is no valid media in the device %s.\n"), print_name());
+ Emsg0(M_FATAL, 0, errmsg);
+ fd = -1;
+ return;
+ }
}
else {
Mmsg(errmsg, _("Could not mount device %s.\n"), print_name());
case BST_MOUNT:
return "BST_MOUNT";
default:
- return "unknown blocked code";
+ return _("unknown blocked code");
}
}
void DEVICE::set_ateof()
{
set_eof();
- file++;
+ if (is_tape()) {
+ file++;
+ }
file_addr = 0;
file_size = 0;
block_num = 0;
return false;
}
/*
- * Avoid infinite loop. ***FIXME*** possibly add code
- * to set EOD or to turn off CAP_FASTFSF if on.
+ * Avoid infinite loop by ensuring we advance.
*/
if (file_num == (int)dev->file) {
struct mtget mt_stat;
Dmsg1(100, "fsf did not advance from file %d\n", file_num);
+ dev->set_ateof();
if (dev_get_os_pos(dev, &mt_stat)) {
Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
- dev->set_ateof();
dev->file = mt_stat.mt_fileno;
- }
- return false;
+ }
+ break;
}
}
}
}
/*
- * Set the position of the device -- only for files
+ * Set the position of the device -- only for files and DVD
* For other devices, there is no generic way to do it.
* Returns: true on succes
* false on error
if (pos < 0) {
berrno be;
dev->dev_errno = errno;
- Pmsg1(000, "Seek error: ERR=%s\n", be.strerror());
+ Pmsg1(000, _("Seek error: ERR=%s\n"), be.strerror());
Mmsg2(dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
dev->print_name(), be.strerror());
ok = false;
}
if (dev->is_tape()) {
stat |= BMT_TAPE;
- Pmsg0(-20," Bacula status:");
- Pmsg2(-20," file=%d block=%d\n", dev->file, dev->block_num);
+ 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) {
berrno be;
dev->dev_errno = errno;
dev->print_name(), be.strerror());
return 0;
}
- Pmsg0(-20, " Device status:");
+ Pmsg0(-20, _(" Device status:"));
#if defined(HAVE_LINUX_OS)
if (GMT_EOF(mt_stat.mt_gstat)) {
}
#endif /* !SunOS && !OSF */
if (dev_cap(dev, CAP_MTIOCGET)) {
- Pmsg2(-20, " file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
+ 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);
+ Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
}
} else {
stat |= BMT_ONLINE | BMT_BOT;
{
struct mtop mt_com;
- if (dev->fd < 0) {
- dev->dev_errno = EBADF;
- Mmsg0(dev->errmsg, _("Bad call to offline_dev. Device not open\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
- return false;
- }
- if (!(dev->is_tape())) {
- return true;
+ if (!dev || dev->fd < 0 || !dev->is_tape()) {
+ return true; /* device not open */
}
dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
switch (func) {
case -1:
- Emsg0(M_ABORT, 0, "Got ENOTTY on read/write!\n");
+ Emsg0(M_ABORT, 0, _("Got ENOTTY on read/write!\n"));
break;
case MTWEOF:
msg = "WTWEOF";
break;
#endif
default:
- bsnprintf(buf, sizeof(buf), "unknown func code %d", func);
+ bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func);
msg = buf;
break;
}
}
/* Remove the last part file if it is empty */
- if (dev->can_append() && (dev->num_parts > 0)) {
+ if (dev->num_parts > 0) {
struct stat statp;
POOL_MEM archive_name(PM_FNAME);
dev->part = dev->num_parts;
dev->part_start = 0;
dev->EndFile = dev->EndBlock = 0;
memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
+ free_volume(dev);
memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
if (dev->tid) {
stop_thread_timer(dev->tid);