*/
DevicePropertyBase device_property_broken_gmt_online;
DevicePropertyBase device_property_fsf;
+DevicePropertyBase device_property_fsf_after_filemark;
DevicePropertyBase device_property_bsf;
DevicePropertyBase device_property_fsr;
DevicePropertyBase device_property_bsr;
DevicePropertyBase device_property_eom;
DevicePropertyBase device_property_bsf_after_eom;
+DevicePropertyBase device_property_nonblocking_open;
DevicePropertyBase device_property_final_filemarks;
void tape_device_register(void);
&response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
device_set_simple_property(d_self, PROPERTY_FSF,
&response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
+ device_set_simple_property(d_self, PROPERTY_FSF_AFTER_FILEMARK,
+ &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
device_set_simple_property(d_self, PROPERTY_BSF,
&response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
device_set_simple_property(d_self, PROPERTY_FSR,
&response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
device_set_simple_property(d_self, PROPERTY_BSF_AFTER_EOM,
&response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
+
+#ifdef DEFAULT_TAPE_NON_BLOCKING_OPEN
+ self->nonblocking_open = TRUE;
+#else
+ self->nonblocking_open = FALSE;
+#endif
+ g_value_set_boolean(&response, self->nonblocking_open);
+ device_set_simple_property(d_self, PROPERTY_NONBLOCKING_OPEN,
+ &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
g_value_unset(&response);
self->final_filemarks = 2;
device_simple_property_get_fn,
tape_device_set_feature_property_fn);
+ device_class_register_property(device_class, PROPERTY_FSF_AFTER_FILEMARK,
+ PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
+ device_simple_property_get_fn,
+ tape_device_set_feature_property_fn);
+
device_class_register_property(device_class, PROPERTY_BSF,
PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
device_simple_property_get_fn,
device_simple_property_get_fn,
tape_device_set_feature_property_fn);
+ device_class_register_property(device_class, PROPERTY_NONBLOCKING_OPEN,
+ PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
+ device_simple_property_get_fn,
+ tape_device_set_feature_property_fn);
+
device_class_register_property(device_class, PROPERTY_FINAL_FILEMARKS,
PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
device_simple_property_get_fn,
self->broken_gmt_online = new_bool;
else if (base->ID == PROPERTY_FSF)
self->fsf = new_bool;
+ else if (base->ID == PROPERTY_FSF_AFTER_FILEMARK)
+ self->fsf_after_filemark = new_bool;
else if (base->ID == PROPERTY_BSF)
self->bsf = new_bool;
else if (base->ID == PROPERTY_FSR)
self->eom = new_bool;
else if (base->ID == PROPERTY_BSF_AFTER_EOM)
self->bsf_after_eom = new_bool;
+ else if (base->ID == PROPERTY_NONBLOCKING_OPEN)
+ self->nonblocking_open = new_bool;
else
return FALSE; /* shouldn't happen */
G_TYPE_BOOLEAN, "fsf",
"Does this drive support the MTFSF command?");
+ device_property_fill_and_register(&device_property_fsf_after_filemark,
+ G_TYPE_BOOLEAN, "fsf_after_filemark",
+ "Does this drive needs a FSF if a filemark is already read?");
+
device_property_fill_and_register(&device_property_bsf,
G_TYPE_BOOLEAN, "bsf",
"Does this drive support the MTBSF command?" );
"bsf_after_eom",
"Does this drive require an MTBSF after MTEOM in order to append?" );
+ device_property_fill_and_register(&device_property_nonblocking_open,
+ G_TYPE_BOOLEAN,
+ "nonblocking_open",
+ "Does this drive require a open with O_NONBLOCK?" );
+
device_property_fill_and_register(&device_property_final_filemarks,
G_TYPE_UINT, "final_filemarks",
"How many filemarks to write after the last tape file?" );
register_device(tape_device_factory, device_prefix_list);
}
+/* Open the tape device, trying various combinations of O_RDWR and
+ O_NONBLOCK. Returns -1 and calls device_set_error for errors
+ On Linux, with O_NONBLOCK, the kernel just checks the state once,
+ whereas it checks it every second for ST_BLOCK_SECONDS if O_NONBLOCK is
+ not given. Amanda already have the code to poll, we want open to check
+ the state only once. */
+
static int try_open_tape_device(TapeDevice * self, char * device_filename) {
int fd;
int save_errno;
DeviceStatusFlags new_status;
- fd = robust_open(device_filename, O_RDWR,0);
+#ifdef O_NONBLOCK
+ int nonblocking = 0;
+
+ if (self->nonblocking_open) {
+ nonblocking = O_NONBLOCK;
+ }
+#endif
+
+#ifdef O_NONBLOCK
+ fd = robust_open(device_filename, O_RDWR | nonblocking, 0);
+ save_errno = errno;
+ if (fd < 0 && nonblocking && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
+ /* Maybe we don't support O_NONBLOCK for tape devices. */
+ fd = robust_open(device_filename, O_RDWR, 0);
+ save_errno = errno;
+ }
+#else
+ fd = robust_open(device_filename, O_RDWR, 0);
save_errno = errno;
+#endif
if (fd >= 0) {
self->write_open_errno = 0;
} else {
- if (errno == EACCES || errno == EPERM) {
+ if (errno == EACCES || errno == EPERM
+#ifdef EROFS
+ || errno == EROFS
+#endif
+ ) {
/* Device is write-protected. */
self->write_open_errno = errno;
- fd = robust_open(device_filename, O_RDONLY,0);
+#ifdef O_NONBLOCK
+ fd = robust_open(device_filename, O_RDONLY | nonblocking, 0);
+ save_errno = errno;
+ if (fd < 0 && nonblocking && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
+ fd = robust_open(device_filename, O_RDONLY, 0);
+ save_errno = errno;
+ }
+#else
+ fd = robust_open(device_filename, O_RDONLY, 0);
save_errno = errno;
+#endif
}
}
+#ifdef O_NONBLOCK
+ /* Clear O_NONBLOCK for operations from now on. */
+ if (fd >= 0 && nonblocking)
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
+ errno = save_errno;
+ /* function continues after #endif */
+
+#endif /* O_NONBLOCK */
if (fd < 0) {
DeviceStatusFlags status_flag = 0;
void
tape_device_set_capabilities(TapeDevice *self,
gboolean fsf, PropertySurety fsf_surety, PropertySource fsf_source,
+ gboolean fsf_after_filemark, PropertySurety faf_surety, PropertySource faf_source,
gboolean bsf, PropertySurety bsf_surety, PropertySource bsf_source,
gboolean fsr, PropertySurety fsr_surety, PropertySource fsr_source,
gboolean bsr, PropertySurety bsr_surety, PropertySource bsr_source,
g_value_set_boolean(&val, fsf);
device_set_simple_property(dself, PROPERTY_FSF, &val, fsf_surety, fsf_source);
+ self->fsf_after_filemark = fsf_after_filemark;
+ g_value_set_boolean(&val, fsf_after_filemark);
+ device_set_simple_property(dself, PROPERTY_FSF_AFTER_FILEMARK, &val, faf_surety, faf_source);
+
self->bsf = bsf;
g_value_set_boolean(&val, bsf);
device_set_simple_property(dself, PROPERTY_BSF, &val, bsf_surety, bsf_source);
difference = file - d_self->file;
/* Check if we already read a filemark. */
- if (d_self->is_eof) {
+ /* If we already read a filemark and the drive automaticaly goes to the
+ next file, then we must reduce the difference by one. */
+ if (d_self->is_eof && !self->fsf_after_filemark) {
difference --;
}
return FALSE;
}
+ d_self->is_eof = FALSE;
d_self->access_mode = ACCESS_NULL;
return TRUE;
result = read(self->fd, buf, *count);
if (result > 0) {
/* Success. By definition, we read a full block. */
+ d_self->is_eof = FALSE;
*count = result;
return RESULT_SUCCESS;
} else if (result == 0) {
+ d_self->is_eof = TRUE;
return RESULT_NO_DATA;
} else {
if (0