]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/btape.c
Clean up some SD message nos.
[bacula/bacula] / bacula / src / stored / btape.c
index f5ba06b07a369576d00fb0d49d15ba2cf47a8afe..c3e961b445b9781121f290a9cf5de529545ad2f5 100644 (file)
@@ -14,7 +14,7 @@
  *
  */
 /*
-   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+   Copyright (C) 2000-2003 Kern Sibbald and John Walker
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -57,8 +57,10 @@ static void scancmd();
 static void rewindcmd();
 static void clearcmd();
 static void wrcmd();
+static void rrcmd();
 static void eodcmd();
 static void fillcmd();
+static void statcmd();
 static void unfillcmd();
 static int flush_block(DEV_BLOCK *block, int dump);
 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
@@ -80,7 +82,6 @@ static uint64_t VolBytes;
 static time_t now;
 static double kbs;
 static long file_index;
-static int verbose = 0;
 static int end_of_tape = 0;
 static uint32_t LastBlock = 0;
 static uint32_t eot_block;
@@ -206,7 +207,7 @@ int main(int argc, char *argv[])
       exit(1);
    }
 
-   jcr = setup_jcr("btape", argv[0], bsr);
+   jcr = setup_jcr("btape", argv[0], bsr, NULL);
    dev = setup_to_access_device(jcr, 0);     /* acquire for write */
    if (!dev) {
       exit(1);
@@ -499,6 +500,14 @@ static void capcmd()
    printf("%sSHORT ", dev->state & ST_SHORT ? "" : "!");
    printf("\n");
 
+   printf(_("Device parameters:\n"));
+   printf("Device name: %s\n", dev->dev_name);
+   printf("File=%u block=%u\n", dev->file, dev->block_num);
+   printf("Min block=%u Max block=%u\n", dev->min_block_size, dev->max_block_size);
+
+   printf("Status:\n");
+   statcmd();
+
 }
 
 /*
@@ -511,10 +520,10 @@ static void rectestcmd()
    DEV_RECORD *rec;
    int i, blkno = 0;
 
-   Pmsg0(0, "Test writting larger and larger records.\n\
-This is a torture test for records.\nI am going to write\n\
-larger and larger records. It will stop when the record size\n\
-plus the header exceeds the block size (by default about 64K\n");
+   Pmsg0(0, "Test writting larger and larger records.\n"
+"This is a torture test for records.\nI am going to write\n"
+"larger and larger records. It will stop when the record size\n"
+"plus the header exceeds the block size (by default about 64K)\n");
 
 
    get_cmd("Do you want to continue? (y/n): ");
@@ -546,6 +555,13 @@ plus the header exceeds the block size (by default about 64K\n");
    sm_check(__FILE__, __LINE__, False);
 }
 
+/*
+ * This test attempts to re-read a block written by Bacula
+ *   normally at the end of the tape. Bacula will then back up
+ *   over the two eof marks, backup over the record and reread
+ *   it to make sure it is valid.  Bacula can skip this validation
+ *   if you set "Backward space record = no"
+ */
 static int re_read_block_test()
 {
    DEV_BLOCK *block;
@@ -553,14 +569,17 @@ static int re_read_block_test()
    int stat = 0;
    int len;
 
-   if (!(dev->capabilities & CAP_EOM)) {
-      Pmsg0(-1, _("Skipping read backwards test because MT_EOM turned off.\n"));
+   if (!(dev->capabilities & CAP_BSR)) {
+      Pmsg0(-1, _("Skipping read backwards test because BSR turned off.\n"));
       return 0;
    }
 
-   Pmsg0(-1, _("\nWrite, backup, and re-read test.\n\n"
+   Pmsg0(-1, _("\n=== Write, backup, and re-read test ===\n\n"
       "I'm going to write three records and two eof's\n"
-      "then backup over the eof's and re-read the last record.\n\n"));
+      "then backup over the eof's and re-read the last record.\n"     
+      "Bacula does this after writing the last block on the\n"
+      "tape to verify that the block was written correctly.\n"
+      "It is not an *essential* feature ...\n\n")); 
    rewindcmd();
    block = new_block(dev);
    rec = new_record();
@@ -597,7 +616,7 @@ static int re_read_block_test()
       Pmsg0(0, _("Error writing block to device.\n")); 
       goto bail_out;
    } else {
-      Pmsg1(0, _("Wrote fourth record of %d bytes.\n"), rec->data_len);
+      Pmsg1(0, _("Wrote third record of %d bytes.\n"), rec->data_len);
    }
    weofcmd();
    weofcmd();
@@ -627,24 +646,38 @@ static int re_read_block_test()
    for (int i=0; i<len; i++) {
       if (rec->data[i] != 3) {
          Pmsg0(0, _("Bad data in record. Test failed!\n"));
-         Pmsg0(0, _("You might try adding:\n\n"
-               "Hardware End of File = No\n\n"
-               "to your Storage daemon's Device resource definition.\n"));
         goto bail_out;
       }
    }
-   Pmsg0(0, _("Re-read test succeeded!\n\n"));
+   Pmsg0(0, _("\nBlock re-read correct. Test succeeded!\n"));
+   Pmsg0(-1, _("=== End Write, backup, and re-read test ===\n\n"));
+
    stat = 1;
 
 bail_out:
    free_block(block);
    free_record(rec);
+   if (stat == 0) {
+      Pmsg0(0, _("This is not terribly serious since Bacula only uses\n"
+                 "this function to verify the last block written to the\n"
+                 "tape. Bacula will skip the last block verification\n"
+                 "if you add:\n\n"
+                  "Backward Space Record = No\n\n"
+                  "to your Storage daemon's Device resource definition.\n"));
+   }   
    return stat;
 }
 
+/*
+ * This test writes some records, then writes an end of file,
+ *   rewinds the tape, moves to the end of the data and attepts
+ *   to append to the tape.  This function is essential for
+ *   Bacula to be able to write multiple jobs to the tape.
+ */
 static int append_test()
 {
-   Pmsg0(-1, _("\n\n=== Append files test. ===\n\n"
+   Pmsg0(-1, _("\n\n=== Append files test ===\n\n"
+               "This test is essential to Bacula.\n\n"
 "I'm going to write one record  in file 0,\n"
 "                   two records in file 1,\n"
 "             and three records in file 2\n\n"));
@@ -661,78 +694,113 @@ static int append_test()
    rewindcmd();
    Pmsg0(0, _("Now moving to end of media.\n"));
    eodcmd();
-   Pmsg2(-1, _("End Append files test.\n\
-We should be in file 3. I am at file %d. This is %s\n\n"), 
+   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) {
-      Pmsg0(-1, _("To correct this problem, you might try adding:\n\n"
-            "Hardware End of Medium = No\n\n"
-            "to your Storage daemon's Device resource definition.\n"));
-      return 0;
+      return -1;
    }
 
-   Pmsg0(-1, _("\nNow I am going to attempt to append to the tape.\n"));
+   Pmsg0(-1, _("\nNow the important part, I am going to attempt to append to the tape.\n\n"));
    wrcmd(); 
    weofcmd();
    rewindcmd();
-   Pmsg0(0, _("Done writing, scanning results ...\n\n"));
+   Pmsg0(-1, _("Done appending, there should be no I/O errors\n\n"));
+   Pmsg0(-1, "Doing Bacula scan of blocks:\n");
    scan_blocks();
-   Pmsg0(-1, _("End Append to the tape test.\n\
-The above scan should have four files of:\n\
-One record, two records, three records, and one record \n\
-respectively each with 64,448 bytes.\n\n"));
-   Pmsg0(-1, _("If the above is not correct, you might try running Bacula\n"
-              "in fixed block mode 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"));
+   Pmsg0(-1, _("End scanning the tape.\n"));
+   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!!!!");
 
-   return 1;
-}
+   if (dev->file != 4) {
+      return -2;
+   }
 
-void append_block_test()  
-{
-   Pmsg0(-1, "\n\n=== Append block test. ===\n\n\
-I'm going to write a block, an EOF, rewind, go to EOM,\n\
-then backspace over the EOF and attempt to append a second\n\
-block in the first file.\n\n");
-   rewindcmd();
-   wrcmd();
-   weofcmd();
-   rewindcmd();
-   eodcmd();
-   Pmsg2(-1, _("We should be at file 1. I am at EOM File=%d. This is %s\n"),
-      dev->file, dev->file == 1 ? "correct!" : "NOT correct!!!!");
-   Pmsg0(0, "Doing backspace file.\n");
-   bsfcmd();
-   Pmsg0(0, _("Write second block, hoping to append to first file.\n"));
-   wrcmd();
-   weofcmd();
-   rewindcmd();
-   Pmsg0(0, _("Done writing, scanning results ...\n\n"));
-   scan_blocks();
-   Pmsg0(-1, _("\nThe above should have one file of two blocks 64,448 bytes each.\n"));
+   return 1;
 }
 
-
-
 /* 
  * This is a general test of Bacula's functions
  *   needed to read and write the tape.
  */
 static void testcmd()
 {
-   re_read_block_test();
+   int stat;
 
-   if (!append_test()) {
-      return;
+   stat = append_test();
+   if (stat == 1) {                  /* OK get out */
+      goto all_done;
+   }
+   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");
+        dev->capabilities &= ~CAP_EOM; /* turn off eom */
+        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"
+                     "to your Device resource in the Storage conf file.\n");
+           goto all_done;
+        }
+        if (stat == -1) {
+            Pmsg0(-1, "\n\nThat appears not to have corrected the problem.\n");
+           goto all_done;
+        }
+        /* Wrong count after append */
+        if (stat == -2) {
+            Pmsg0(-1, "\n\nIt looks like the append failed. Attempting again.\n"
+                     "Setting \"BSF at EOM = yes\" and retrying append test.\n");
+           dev->capabilities |= CAP_BSFATEOM; /* backspace on eom */
+           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"
+                     "    BSR 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");
+      }
    }
 
-   append_block_test();
+all_done:
+   Pmsg0(-1, _("\nThe above Bacula scan should have output identical to what follows.\n"
+        "Please double check it ...\n"
+        "=== Sample correct output ===\n"
+        "1 block of 64448 bytes in file 1\n"
+        "End of File mark.\n"
+        "2 blocks of 64448 bytes in file 2\n"
+        "End of File mark.\n"
+        "3 blocks of 64448 bytes in file 3\n"
+        "End of File mark.\n"
+        "1 block of 64448 bytes in file 4\n" 
+        "End of File mark.\n"
+        "Total files=4, blocks=7, bytes = 451136\n"
+        "=== End sample correct output ===\n\n"));
+
+   Pmsg0(-1, _("If the above scan output is not identical to the\n"
+               "sample output, you MUST correct the problem\n"
+               "or Bacula will not be able to write multiple Jobs to \n"
+               "the tape.\n\n"));
 
+   if (stat == 1) {
+      re_read_block_test();
+   }
 
+   Pmsg0(-1, _("\n=== End Append files test ===\n"));
+   
 }
 
 /* Forward space a file */
@@ -757,22 +825,6 @@ static void fsrcmd()
    Pmsg0(0, "Forward spaced one record.\n");
 }
 
-/* DEPRECATED DO NOT USE */
-static void rdcmd()
-{
-#ifdef xxxxx
-   int stat;
-
-   if (!read_dev(dev, buf, 512*126)) {
-      Pmsg1(0, "Bad status from read. ERR=%s\n", strerror_dev(dev));
-      return;
-   }
-   Pmsg1(10, "Read %d bytes\n", stat);
-#else
-   printf("Rdcmd no longer implemented.\n");
-#endif
-}
-
 
 /*
  * Write a Bacula block to the tape
@@ -813,6 +865,32 @@ bail_out:
    sm_check(__FILE__, __LINE__, False);
 }
 
+/* 
+ * Read a record from the tape
+ */
+static void rrcmd()
+{
+   char *buf;
+   int stat, len;
+
+   if (!get_cmd("Enter length to read: ")) {
+      return;
+   }
+   len = atoi(cmd);
+   if (len < 0 || len > 1000000) {
+      Pmsg0(0, _("Bad length entered, using default of 1024 bytes.\n"));
+      len = 1024;
+   }
+   buf = (char *)malloc(len);
+   stat = read(dev->fd, buf, len);
+   if (stat > 0 && stat <= len) {
+      errno = 0;
+   }
+   Pmsg3(0, _("Read of %d bytes gives stat=%d. ERR=%s\n"),
+      len, stat, strerror(errno));
+   free(buf);
+}
+
 
 /*
  * Scan tape by reading block by block. Report what is
@@ -1043,7 +1121,7 @@ This may take a long time. I.e. hours! ...\n\n");
     *  subroutine.
     */
    Dmsg0(100, "just before acquire_device\n");
-   if (!acquire_device_for_append(jcr, dev, block)) {
+   if (!(dev=acquire_device_for_append(jcr, dev, block))) {
       set_jcr_job_status(jcr, JS_ErrorTerminated);
       free_block(block);
       return;
@@ -1079,7 +1157,7 @@ This may take a long time. I.e. hours! ...\n\n");
     */
    jcr->VolFirstFile = 0;
    time(&jcr->run_time);             /* start counting time for rates */
-   for (file_index = 0; ok && !job_cancelled(jcr); ) {
+   for (file_index = 0; ok && !job_canceled(jcr); ) {
       uint64_t *lp;
       rec.VolSessionId = jcr->VolSessionId;
       rec.VolSessionTime = jcr->VolSessionTime;
@@ -1145,7 +1223,7 @@ This may take a long time. I.e. hours! ...\n\n");
    if (stop > 0) {
       Dmsg0(000, "Write_end_session_label()\n");
       /* Create Job status for end of session label */
-      if (!job_cancelled(jcr) && ok) {
+      if (!job_canceled(jcr) && ok) {
         set_jcr_job_status(jcr, JS_Terminated);
       } else if (!ok) {
         set_jcr_job_status(jcr, JS_ErrorTerminated);
@@ -1446,7 +1524,6 @@ static struct cmdstruct commands[] = {
  {"label",      labelcmd,     "write a Bacula label to the tape"},
  {"load",       loadcmd,      "load a tape"},
  {"quit",       quitcmd,      "quit btape"},   
- {"rd",         rdcmd,        "read tape"},
  {"readlabel",  readlabelcmd, "read and print the Bacula tape label"},
  {"rectest",    rectestcmd,   "test record handling functions"},
  {"rewind",     rewindcmd,    "rewind the tape"},
@@ -1454,7 +1531,8 @@ static struct cmdstruct commands[] = {
  {"status",     statcmd,      "print tape status"},
  {"test",       testcmd,      "General test Bacula tape functions"},
  {"weof",       weofcmd,      "write an EOF on the tape"},
- {"wr",         wrcmd,        "write a single record of 2048 bytes"}, 
+ {"wr",         wrcmd,        "write a single Bacula block"}, 
+ {"rr",         rrcmd,        "read a single record"},
             };
 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
 
@@ -1493,7 +1571,7 @@ static void helpcmd()
 static void usage()
 {
    fprintf(stderr, _(
-"\nVersion: " VERSION " (" DATE ")\n\n"
+"\nVersion: " VERSION " (" BDATE ")\n\n"
 "Usage: btape [-c config_file] [-d debug_level] [device_name]\n"
 "       -c <file>   set configuration file to file\n"
 "       -dnn        set debug level to nn\n"