Imported Upstream version 2.6.1p2
[debian/amanda] / device-src / tape-device.c
index f63e35a0fe78f92288acffc38c459a889daf7c01..77e7bfa068a27712a61dc8ba6e899e761ee80a76 100644 (file)
@@ -57,11 +57,13 @@ typedef enum {
  */
 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);
@@ -165,6 +167,8 @@ tape_device_init (TapeDevice * self) {
            &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,
@@ -175,6 +179,15 @@ tape_device_init (TapeDevice * self) {
            &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;
@@ -275,6 +288,11 @@ tape_device_base_init (TapeDeviceClass * c)
            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,
@@ -300,6 +318,11 @@ tape_device_base_init (TapeDeviceClass * c)
            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,
@@ -354,6 +377,8 @@ tape_device_set_feature_property_fn(Device *p_self, DevicePropertyBase *base,
        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)
@@ -364,6 +389,8 @@ tape_device_set_feature_property_fn(Device *p_self, DevicePropertyBase *base,
        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 */
 
@@ -459,6 +486,10 @@ void tape_device_register(void) {
                                       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?" );
@@ -481,6 +512,11 @@ void tape_device_register(void) {
                                       "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?" );
@@ -489,23 +525,69 @@ void tape_device_register(void) {
     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;
@@ -577,6 +659,7 @@ tape_device_open_device (Device * d_self, char * device_name G_GNUC_UNUSED,
 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,
@@ -599,6 +682,10 @@ tape_device_set_capabilities(TapeDevice *self,
     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);
@@ -1050,7 +1137,9 @@ tape_device_seek_file (Device * d_self, guint file) {
     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 --;
     }
 
@@ -1196,6 +1285,7 @@ tape_device_finish (Device * d_self) {
         return FALSE;
     }
 
+    d_self->is_eof = FALSE;
     d_self->access_mode = ACCESS_NULL;
 
     return TRUE;
@@ -1219,9 +1309,11 @@ tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
         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