]> git.sur5r.net Git - bacula/bacula/commitdiff
Autochanger test, FastSpaceForward implement+test
authorKern Sibbald <kern@sibbald.com>
Sat, 22 Nov 2003 08:26:04 +0000 (08:26 +0000)
committerKern Sibbald <kern@sibbald.com>
Sat, 22 Nov 2003 08:26:04 +0000 (08:26 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@812 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/kernstodo
bacula/src/stored/btape.c
bacula/src/stored/butil.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/stored_conf.c
bacula/src/stored/stored_conf.h

index 47ee0b99e8f8d90afdd4e1270bb86b9912166517..ad971e089c4e106bf0c0cc17614191d51e74d470 100644 (file)
@@ -47,25 +47,24 @@ For 1.33 Testing/Documentation:
                 
 
 For 1.33
-- Optimize fsf not to read.
-- Use ioctl() fsf if it exists. Figure out where we are from
-  the mt_status command. Use slow fsf only if other does not work.
 - Add flag to write only one EOF mark on the tape.
 - Implement autochanger testing in btape "test" command.
-- Make sure that Volumes are recycled based on "Least recently used"
-  rather than lowest MediaId.
 - Implement RestoreJobRetention? Maybe better "JobRetention" in a Job,
   which would take precidence over the Catalog "JobRetention".
 - Implement Label Format in Add and Label console commands.
-- Enhance "update slots" to include a "scan" feature
-  scan 1; scan 1-5; scan 1,2,4 ...  to update the catalog 
-- Allow a slot or range of slots on the label barcodes command.
-- Finish implementation of Verify=DiskToCatalog
 - Possibly up network buffers to 65K.
 - Keep last 5 or 10 completed jobs and show them in a similar list.
 - Make a Running Jobs: output similar to current Scheduled Jobs:
 
 After 1.33:
+- Create VolAddr for disk files in place of VolFile and VolBlock. This
+  is needed to properly specify ranges.
+- Print bsmtp output to job report so that problems will be seen.
+- Make mark/unmark report how many files marked/unmarked.
+- Have some way to estimate the restore size or have it printed.
+- Pass the number of files to be restored to the FD for reporting 
+- Add progress of files/bytes to SD and FD.
+- Implement lmark to list everyfile marked.
 - Don't continue Restore if no files selected.
 - Print warning message if FileId > 4 billion
 - do a "messages" before the first prompt in Console
@@ -883,6 +882,7 @@ Done: (see kernsdone for more)
 - Implement ClientRunBeforeJob and ClientRunAfterJob.
 - Implement forward spacing block/file: position_device(bsr) --
   just before read_block_from_device();
+=== for 1.33
 - Change console to bconsole.
 - Change smtp to bsmtp.
 - Fix time difference problem between Bacula and Client
@@ -898,3 +898,13 @@ Done: (see kernsdone for more)
        Files=21,003 Bytes=253,954,408 Bytes/sec=2,919,016
        FDReadSeqNo=192,134 in_msg=129830 out_msg=5 fd=7
 - Upgrade to cygwin 1.5
+- Optimize fsf not to read.
+- Use ioctl() fsf if it exists. Figure out where we are from
+  the mt_status command. Use slow fsf only if other does not work.
+- Enhance "update slots" to include a "scan" feature
+  scan 1; scan 1-5; scan 1,2,4 ...  to update the catalog 
+- Allow a slot or range of slots on the label barcodes command.
+- Finish implementation of Verify=DiskToCatalog
+- Make sure that Volumes are recycled based on "Least recently used"
+  rather than lowest MediaId.
+
index 39df9d4911c754e4119da0d83d46e422b5d387d5..8adcdc0e0beb06526ca00a6005146a145ce4ac81 100644 (file)
@@ -70,6 +70,9 @@ static void scan_blocks();
 static void set_volume_name(char *VolName, int volnum);
 static void rawfill_cmd();
 static void bfill_cmd();
+static bool open_the_device();
+static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd);
+static void autochangercmd();
 
 
 /* Static variables */
@@ -118,7 +121,6 @@ int get_cmd(char *prompt);
 int main(int argc, char *argv[])
 {
    int ch;
-   DEV_BLOCK *block;
 
    /* Sanity checks */
    if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
@@ -205,20 +207,9 @@ int main(int argc, char *argv[])
    if (!dev) {
       exit(1);
    }
-   block = new_block(dev);
-   lock_device(dev);
-   if (!(dev->state & ST_OPENED)) {
-      Dmsg0(129, "Opening device.\n");
-      if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) {
-         Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
-        unlock_device(dev);
-        free_block(block);
-        goto terminate;
-      }
+   if (!open_the_device()) {
+      goto terminate;
    }
-   Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
-   unlock_device(dev);
-   free_block(block);
 
    Dmsg0(200, "Do tape commands\n");
    do_tape_cmds();
@@ -265,6 +256,28 @@ static void terminate_btape(int stat)
    exit(stat);
 }
 
+static bool open_the_device()
+{
+   DEV_BLOCK *block;
+   
+   block = new_block(dev);
+   lock_device(dev);
+   if (!(dev->state & ST_OPENED)) {
+      Dmsg1(200, "Opening device %s\n", jcr->VolumeName);
+      if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) {
+         Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
+        unlock_device(dev);
+        free_block(block);
+        return false;
+      }
+   }
+   Dmsg1(000, "open_dev %s OK\n", dev_name(dev));
+   unlock_device(dev);
+   free_block(block);
+   return true;
+}
+
+
 void quitcmd()
 {
    quit = 1;
@@ -275,27 +288,8 @@ void quitcmd()
  */
 static void labelcmd()
 {
-   DEVRES *device;
-   int found = 0;
-
-   LockRes();
-   for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
-      if (strcmp(device->device_name, dev->dev_name) == 0) {
-        jcr->device = device;        /* Arggg a bit of duplication here */
-        device->dev = dev;
-        dev->device = device;
-        found = 1;
-        break;
-      }
-   } 
-   UnlockRes();
-   if (!found) {
-      Pmsg2(0, "Could not find device %s in %s\n", dev->dev_name, configfile);
-      return;
-   }
-
    if (VolumeName) {
-      strcpy(cmd, VolumeName);
+      bstrncpy(cmd, VolumeName, sizeof(cmd));
    } else {
       if (!get_cmd("Enter Volume Name: ")) {
         return;
@@ -307,7 +301,7 @@ static void labelcmd()
          Pmsg1(0, "Device open failed. ERR=%s\n", strerror_dev(dev));
       }
    }
-   write_volume_label_to_dev(jcr, device, cmd, "Default");
+   write_volume_label_to_dev(jcr, jcr->device, cmd, "Default");
 }
 
 /*
@@ -709,6 +703,225 @@ static int append_test()
    return 1;
 }
 
+
+/*
+ * This test exercises the autochanger
+ */
+static int autochanger_test()
+{
+   POOLMEM *results, *changer;
+   int slot, status, loaded;
+   int timeout = 120;
+   int sleep_time = 0;
+
+   if (!dev_cap(dev, CAP_AUTOCHANGER)) {
+      return 1;
+   }
+   if (!(jcr->device && jcr->device->changer_name && jcr->device->changer_command)) {
+      Pmsg0(-1, "\nAutochanger enabled, but no name or no command device specified.\n");
+      return 1;
+   }
+
+   Pmsg0(-1, "\nTo test the autochanger you must have a blank tape in Slot 1.\n"
+             "I'm going to write on it.\n");
+   if (!get_cmd("\nDo you wish to continue with the Autochanger test? (y/n): ")) {
+      return 0;
+   }
+   if (cmd[0] != 'y' && cmd[0] != 'Y') {
+      return 0;
+   }
+
+   Pmsg0(-1, _("\n\n=== Autochanger test ===\n\n"));
+
+   results = get_pool_memory(PM_MESSAGE);
+   changer = get_pool_memory(PM_FNAME);
+
+try_again:
+   slot = 1;
+   jcr->VolCatInfo.Slot = slot;
+   /* Find out what is loaded, zero means device is unloaded */
+   Pmsg0(-1, _("3301 Issuing autochanger \"loaded\" command.\n"));
+   changer = edit_device_codes(jcr, changer, jcr->device->changer_command, 
+                "loaded");
+   status = run_program(changer, timeout, results);
+   Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results);
+   if (status == 0) {
+      loaded = atoi(results);
+   } else {
+      Pmsg1(-1, _("3991 Bad autochanger \"load slot\" status=%d.\n"), status);
+      loaded = -1;             /* force unload */
+      goto bail_out;
+   }
+   if (loaded) {
+      Pmsg1(-1, "Slot %d loaded. I am going to unload it.\n", loaded);
+   } else {
+      Pmsg0(-1, "Nothing loaded into the drive. OK.\n");
+   }
+   Dmsg1(100, "Results from loaded query=%s\n", results);
+   if (loaded) {
+      offline_or_rewind_dev(dev);
+      /* We are going to load a new tape, so close the device */
+      force_close_dev(dev);
+      Pmsg0(-1, _("3302 Issuing autochanger \"unload\" command.\n"));
+      changer = edit_device_codes(jcr, changer, 
+                     jcr->device->changer_command, "unload");
+      status = run_program(changer, timeout, NULL);
+      Pmsg2(-1, "unload status=%s %d\n", status==0?"OK":"Bad", status);
+   }
+
+   /*
+    * Load the Slot 1
+    */
+   Pmsg1(-1, _("3303 Issuing autochanger \"load slot %d\" command.\n"), slot);
+   changer = edit_device_codes(jcr, changer, jcr->device->changer_command, "load");
+   Dmsg1(200, "Changer=%s\n", changer);
+   status = run_program(changer, timeout, NULL);
+   if (status == 0) {
+      Pmsg1(-1,  _("3304 Autochanger \"load slot %d\" status is OK.\n"), slot);
+   } else {
+      Pmsg1(-1,  _("3992 Bad autochanger \"load slot\" status=%d.\n"), status);
+      goto bail_out;
+   }
+
+   if (!open_the_device()) {
+      goto bail_out;
+   }
+   bmicrosleep(sleep_time, 0);
+   if (!rewind_dev(dev)) {
+      Pmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
+      clrerror_dev(dev, -1);
+      Pmsg0(-1, "\nThe test failed, probably because you need to put\n"
+                "a longer sleep time in the mtx-script in the load) case.\n" 
+                "Adding a 30 second sleep and trying again ...\n");
+      sleep_time += 30;
+      goto try_again;
+   } else {
+      Pmsg1(0, "Rewound %s\n", dev_name(dev));
+   }
+      
+   if ((status = weof_dev(dev, 1)) < 0) {
+      Pmsg2(0, "Bad status from weof %d. ERR=%s\n", status, strerror_dev(dev));
+      goto bail_out;
+   } else {
+      Pmsg1(0, "Wrote EOF to %s\n", dev_name(dev));
+   }
+
+   if (sleep_time) {
+      Pmsg1(-1, "\nThe test worked this time. Please add:\n\n"
+                "   sleep %d\n\n"
+                "to your mtx-changer script in the load) case.\n\n",
+               sleep_time);
+   } else {
+      Pmsg0(-1, "\nThe test autochanger worked!!\n\n");
+   }
+
+   free_pool_memory(changer);
+   free_pool_memory(results);
+   return 1;
+
+
+bail_out:
+   free_pool_memory(changer);
+   free_pool_memory(results);
+   Pmsg0(-1, "You must correct this error or the Autochanger will not work.\n");
+   return -2;
+}
+
+static void autochangercmd()
+{
+   autochanger_test();
+}
+
+
+/*
+ * This test assumes that the append test has been done,
+ *   then it tests the fsf function.
+ */
+static int fsf_test()
+{
+   bool set_off = false;
+   
+   Pmsg0(-1, _("\n\n=== Forward space files test ===\n\n"
+               "This test is essential to Bacula.\n\n"
+               "I'm going to write five files then test forward spacing\n\n"));
+   rewindcmd();
+   wrcmd();
+   weofcmd();     /* end file 0 */
+   wrcmd();
+   wrcmd();
+   weofcmd();     /* end file 1 */
+   wrcmd();
+   wrcmd();
+   wrcmd();
+   weofcmd();    /* end file 2 */
+   wrcmd();
+   wrcmd();
+   weofcmd();    /* end file 3 */
+   wrcmd();
+   weofcmd();    /* end file 4 */
+
+test_again:
+   rewindcmd();
+   Pmsg0(0, _("Now forward spacing 1 file.\n"));
+   if (!fsf_dev(dev, 1)) {
+      Pmsg1(0, "Bad status from fsr. ERR=%s\n", strerror_dev(dev));
+      goto bail_out;
+   }
+   Pmsg2(-1, _("We should be in file 1. I am at file %d. This is %s\n"), 
+      dev->file, dev->file == 1 ? "correct!" : "NOT correct!!!!");
+
+   if (dev->file != 1) {
+      goto bail_out;
+   }
+
+   Pmsg0(0, _("Now forward spacing 2 files.\n"));
+   if (!fsf_dev(dev, 2)) {
+      Pmsg1(0, "Bad status from fsr. ERR=%s\n", strerror_dev(dev));
+      goto bail_out;
+   }
+   Pmsg2(-1, _("We should be in file 3. I am at file %d. This is %s\n"), 
+      dev->file, dev->file == 3 ? "correct!" : "NOT correct!!!!");
+
+   if (dev->file != 3) {
+      goto bail_out;
+   }
+
+   rewindcmd();
+   Pmsg0(0, _("Now forward spacing 4 files.\n"));
+   if (!fsf_dev(dev, 4)) {
+      Pmsg1(0, "Bad status from fsr. ERR=%s\n", strerror_dev(dev));
+      goto bail_out;
+   }
+   Pmsg2(-1, _("We should be in file 4. I am at file %d. This is %s\n"), 
+      dev->file, dev->file == 4 ? "correct!" : "NOT correct!!!!");
+
+   if (dev->file != 4) {
+      goto bail_out;
+   }
+   if (set_off) {
+      Pmsg0(-1, "The test worked this time. Please add:\n\n"
+                "   Fast Forward Space File = no\n\n"
+                "to your Device resource for this drive.\n");
+   }
+   return 1;
+
+bail_out:
+   Pmsg0(-1, _("\nThe forward space file test failed.\n"));
+   if (dev_cap(dev, CAP_FASTFSF)) {
+      Pmsg0(-1, "You have Fast Forward Space File enabled.\n"
+              "I am turning it off then retring the test.\n");
+      dev->capabilities &= ~CAP_FASTFSF;
+      set_off = true;
+      goto test_again;
+   }
+   Pmsg0(-1, "You must correct this error or Bacula will not work.\n");
+   return -2;
+}
+
+
+
+
+
 /* 
  * This is a general test of Bacula's functions
  *   needed to read and write the tape.
@@ -724,12 +937,16 @@ static void testcmd()
    if (stat == -1) {                 /* first test failed */
       if (dev_cap(dev, CAP_EOM)) {
          Pmsg0(-1, "\nAppend test failed. Attempting again.\n"
-                   "Setting \"Hardware End of Medium = no\" and retrying append test.\n\n");
+                   "Setting \"Hardware End of Medium = no\n"
+                   "    and \"Fast Forward Space File = no\n"
+                   "and retrying append test.\n\n");
         dev->capabilities &= ~CAP_EOM; /* turn off eom */
+        dev->capabilities &= ~CAP_FASTFSF; /* turn off fast fsf */
         stat = append_test();
         if (stat == 1) {
             Pmsg0(-1, "\n\nIt looks like the test worked this time, please add:\n\n"
                      "    Hardware End of Medium = No\n\n"
+                     "    Fast Forward Space File = No\n"
                      "to your Device resource in the Storage conf file.\n");
            goto all_done;
         }
@@ -746,23 +963,25 @@ static void testcmd()
            if (stat == 1) {
                Pmsg0(-1, "\n\nIt looks like the test worked this time, please add:\n\n"
                      "    Hardware End of Medium = No\n"
+                     "    Fast Forward Space File = No\n"
                      "    BSF at EOM = yes\n\n"
                      "to your Device resource in the Storage conf file.\n");
               goto all_done;
            }
         }
 
-         Pmsg0(-1, "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
-               "Unable to correct the problem. You MUST fix this\n"
-                "problem before Bacula can use your tape drive correctly\n");
-         Pmsg0(-1, "\nPerhaps running Bacula in fixed block mode will work.\n"
-               "Do so by setting:\n\n"
-               "Minimum Block Size = nnn\n"
-               "Maximum Block Size = nnn\n\n"
-               "in your Storage daemon's Device definition.\n"
-               "nnn must match your tape driver's block size.\n"
-               "This, however, is not really an ideal solution.\n");
       }
+      Pmsg0(-1, "\nAppend test failed.\n\n");
+      Pmsg0(-1, "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+            "Unable to correct the problem. You MUST fix this\n"
+             "problem before Bacula can use your tape drive correctly\n");
+      Pmsg0(-1, "\nPerhaps running Bacula in fixed block mode will work.\n"
+            "Do so by setting:\n\n"
+            "Minimum Block Size = nnn\n"
+            "Maximum Block Size = nnn\n\n"
+            "in your Storage daemon's Device definition.\n"
+            "nnn must match your tape driver's block size.\n"
+            "This, however, is not really an ideal solution.\n");
    }
 
 all_done:
@@ -789,6 +1008,10 @@ all_done:
       re_read_block_test();
    }
 
+   fsf_test();                       /* do fast forward space file test */
+
+   autochanger_test();               /* do autochanger test */
+
    Pmsg0(-1, _("\n=== End Append files test ===\n"));
    
 }
@@ -1676,6 +1899,7 @@ static void bfill_cmd()
 
 struct cmdstruct { char *key; void (*func)(); char *help; }; 
 static struct cmdstruct commands[] = {
+ {"autochanger", autochangercmd, "test autochanger"},
  {"bsf",        bsfcmd,       "backspace file"},
  {"bsr",        bsrcmd,       "backspace record"},
  {"bfill",      bfill_cmd,    "fill tape using Bacula writes"},
@@ -1876,3 +2100,81 @@ static void set_volume_name(char *VolName, int volnum)
    pm_strcpy(&jcr->VolumeName, VolName);
    bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
 }
+
+/*
+ * Edit codes into ChangerCommand
+ *  %% = %
+ *  %a = archive device name
+ *  %c = changer device name
+ *  %f = Client's name
+ *  %j = Job name
+ *  %o = command
+ *  %s = Slot base 0
+ *  %S = Slot base 1
+ *  %v = Volume name
+ *
+ *
+ *  omsg = edited output message
+ *  imsg = input string containing edit codes (%x)
+ *  cmd = command string (load, unload, ...) 
+ *
+ */
+static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) 
+{
+   char *p;
+   const char *str;
+   char add[20];
+
+   *omsg = 0;
+   Dmsg1(400, "edit_device_codes: %s\n", imsg);
+   for (p=imsg; *p; p++) {
+      if (*p == '%') {
+        switch (*++p) {
+         case '%':
+            str = "%";
+           break;
+         case 'a':
+           str = dev_name(jcr->device->dev);
+           break;
+         case 'c':
+           str = NPRT(jcr->device->changer_name);
+           break;
+         case 'o':
+           str = NPRT(cmd);
+           break;
+         case 's':
+            sprintf(add, "%d", jcr->VolCatInfo.Slot - 1);
+           str = add;
+           break;
+         case 'S':
+            sprintf(add, "%d", jcr->VolCatInfo.Slot);
+           str = add;
+           break;
+         case 'j':                    /* Job name */
+           str = jcr->Job;
+           break;
+         case 'v':
+           str = NPRT(jcr->VolumeName);
+           break;
+         case 'f':
+           str = NPRT(jcr->client_name);
+           break;
+
+        default:
+            add[0] = '%';
+           add[1] = *p;
+           add[2] = 0;
+           str = add;
+           break;
+        }
+      } else {
+        add[0] = *p;
+        add[1] = 0;
+        str = add;
+      }
+      Dmsg1(400, "add_str %s\n", str);
+      pm_strcat(&omsg, (char *)str);
+      Dmsg1(400, "omsg=%s\n", omsg);
+   }
+   return omsg;
+}
index a23bb1646f796a553174a76754907bc6707772fb..4c4deafb288c50e0963d26d6577d19eae42f8608 100644 (file)
@@ -97,8 +97,10 @@ DEVICE *setup_to_access_device(JCR *jcr, int read_access)
           jcr->dev_name, configfile);
       return NULL;
    }
+   jcr->device = device;
    
    dev = init_dev(NULL, device);
+   jcr->device->dev = dev;
    if (!dev || !open_device(dev)) {
       Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), jcr->dev_name);
       return NULL;
index f8e2f395eb296be03ac40c50e4727a58c8fca7d4..121b989468a990247ac64d34bb1cf4a3acf29443 100644 (file)
@@ -703,6 +703,7 @@ int offline_or_rewind_dev(DEVICE *dev)
 int
 fsf_dev(DEVICE *dev, int num)
 { 
+   struct mtget mt_stat;
    struct mtop mt_com;
    int stat = 0;
 
@@ -724,13 +725,51 @@ fsf_dev(DEVICE *dev, int num)
    if (dev->state & ST_EOF) {
       Dmsg0(200, "ST_EOF set on entry to FSF\n");
    }
-   if (dev->state & ST_EOT) {
-      Dmsg0(200, "ST_EOT set on entry to FSF\n");
-   }
       
    Dmsg0(29, "fsf_dev\n");
    dev->block_num = 0;
-   if (dev_cap(dev, CAP_FSF)) {
+   /*
+    * 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 over the end of data mark.
+    */
+   if (dev_cap(dev, CAP_FSF) && dev_cap(dev, CAP_FASTFSF)) {
+      mt_com.mt_op = MTFSF;
+      mt_com.mt_count = num;
+      stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+      if (stat < 0) {                /* error => EOT */
+        dev->state |= ST_EOT;
+         Dmsg0(200, "Set ST_EOT\n");
+        clrerror_dev(dev, MTFSF);
+         Mmsg2(&dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
+           dev->dev_name, strerror(dev->dev_errno));
+         Dmsg1(200, "%s", dev->errmsg);
+        return 0;
+      } else if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
+           dev->state |= ST_EOT;
+           clrerror_dev(dev, MTFSF);
+           dev->dev_errno = errno;
+            Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
+              dev->dev_name, strerror(dev->dev_errno));
+            Dmsg1(200, "%s", dev->errmsg);
+           return 0;
+      }
+      Dmsg2(200, "fsf file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
+      dev->file = mt_stat.mt_fileno;
+      dev->state |= ST_EOF;    /* just read EOF */
+      dev->file_addr = 0;
+      return 1;
+
+   /* 
+    * 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 (dev_cap(dev, CAP_FSF)) {
       POOLMEM *rbuf;
       int rbuf_len;
       Dmsg0(200, "FSF has cap_fsf\n");
@@ -1122,7 +1161,7 @@ clrerror_dev(DEVICE *dev, int func)
 {
    /* Read and clear SCSI error status */
    union mterrstat mt_errstat;
-   Pmsg2(000, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev->dev_errno,
+   Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev->dev_errno,
       strerror(dev->dev_errno));
    ioctl(dev->fd, MTIOCERRSTAT, (char *)&mt_errstat);
 }
index 53969ba5aa482ea536d93db56b0e73f4e27134c7..61e7703035818caf49068c41b0529c477e1364f3 100644 (file)
@@ -82,6 +82,7 @@
 #define CAP_OFFLINEUNMOUNT (1<<13)    /* Offline before unmount */
 #define CAP_STREAM         (1<<14)    /* Stream device */
 #define CAP_BSFATEOM       (1<<15)    /* Backspace file at EOM */
+#define CAP_FASTFSF        (1<<16)    /* Fast forward space file */
 
 /* Test state */
 #define dev_state(dev, st_state) ((dev)->state & (st_state))
index 28c1d578721f35ab0af809d9117a7976b64c5e8b..fd26b51be2e28fdefcd2c413cd2c53b64a21db2e 100644 (file)
@@ -92,6 +92,7 @@ static struct res_items dev_items[] = {
    {"bsfateom",              store_yesno,  ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
    {"forwardspacerecord",    store_yesno,  ITEM(res_dev.cap_bits), CAP_FSR,  ITEM_DEFAULT, 1},
    {"forwardspacefile",      store_yesno,  ITEM(res_dev.cap_bits), CAP_FSF,  ITEM_DEFAULT, 1},
+   {"fastforwardspacefile",  store_yesno,  ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
    {"removablemedia",        store_yesno,  ITEM(res_dev.cap_bits), CAP_REM,  ITEM_DEFAULT, 1},
    {"randomaccess",          store_yesno,  ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
    {"automaticmount",        store_yesno,  ITEM(res_dev.cap_bits), CAP_AUTOMOUNT,  ITEM_DEFAULT, 0},
index 14ac5972f5462d530a245785925cc789ea684c23..7cf81d72d8e0a936c1631d07eb7923030c832ebe 100644 (file)
@@ -75,7 +75,7 @@ struct DEVRES {
    char *device_name;                 /* Archive device name */
    char *changer_name;                /* Changer device name */
    char *changer_command;             /* Changer command  -- external program */
-   int  cap_bits;                     /* Capabilities of this device */
+   uint32_t cap_bits;                 /* Capabilities of this device */
    uint32_t max_changer_wait;         /* Changer timeout */
    uint32_t max_rewind_wait;          /* maximum secs to wait for rewind */
    uint32_t max_open_wait;            /* maximum secs to wait for open */