]> git.sur5r.net Git - bacula/bacula/commitdiff
btape updates + documentation -- see kes09Oct02
authorKern Sibbald <kern@sibbald.com>
Wed, 9 Oct 2002 13:27:23 +0000 (13:27 +0000)
committerKern Sibbald <kern@sibbald.com>
Wed, 9 Oct 2002 13:27:23 +0000 (13:27 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@168 91ce42f0-d328-0410-95d8-f526ca767f89

14 files changed:
bacula/ChangeLog
bacula/kernstodo
bacula/src/dird/backup.c
bacula/src/dird/msgchan.c
bacula/src/dird/restore.c
bacula/src/filed/backup.c
bacula/src/filed/job.c
bacula/src/jcr.h
bacula/src/stored/Makefile.in
bacula/src/stored/bextract.c
bacula/src/stored/bls.c
bacula/src/stored/btape.c
bacula/src/stored/label.c
bacula/src/version.h

index 638ccc19bdc8e197af369407b3cadd2f76c5a6ea..3840e1136b2f37ff7fa8db4a2a01742c157093c0 100644 (file)
@@ -1,5 +1,27 @@
 
-2002-xx-xx Version 1.26 (04Oct02)
+2002-xx-xx Version 1.26 (08Oct02)
+General: from kes09Oct02
+- More documentation.
+- Implemented new fill command in btape that permits filling
+  a tape and then reading it back to ensure that it works
+  with Bacula.
+
+Changes submitted this submission:
+- Added ReadBytes to JCR, which contains Job bytes read by
+  FD, JobBytes contains compressed output of FD.
+- Modified FD to pass back JobStatus, ReadBytes, JobBytes, ...
+  for backup jobs.  This is upward compatible.
+- Modified backup termination status report to contain the
+  compression ratio 100 * (1 - compressed-bytes/uncompressed-bytes)
+  This will always be zero if no software compression was
+  done, or if you are using a version 1.25 or older FD.
+- Pickup Job termination status of FD in backup, so now
+  the termination status represents the state of all three
+  daemons.
+- Implemented new fill command in btape that permits filling
+  a tape and then reading it back to ensure that it works
+  with Bacula.
+
 General: From kes06Oct02
 - Implemented first major cut of bscan -- program to scan a tape
   and recreate a Bacula catalog.
index 602bb7201afbc7c8bba0324ddbc41dfc93782584..96ebaa9e752161d2053608fe22630c94bb96d8a5 100644 (file)
@@ -28,8 +28,6 @@ From Chuck:
 =======
 
 - Figure out why my Catalog size keeps growing.
-- Document bscan.
-- Document Restore.
 
 - Make SD disallow writing on Volume with fewer files than in
   the catalog.
@@ -554,3 +552,6 @@ Longer term to do:
 
 
 Done: (see kernsdone for more)
+- Document bscan.
+- Document Restore.
+
index 09917fbe726468571d589f7c77f95b1d497bf80d..decff941a936845d50b56b8eb9995b9b78361619 100644 (file)
@@ -47,9 +47,11 @@ static char storaddr[]  = "storage address=%s port=%d\n";
 static char levelcmd[]  = "level = %s%s\n";
 
 /* Responses received from File daemon */
-static char OKbackup[] = "2000 OK backup\n";
-static char OKstore[]  = "2000 OK storage\n";
-static char OKlevel[]  = "2000 OK level\n";
+static char OKbackup[]  = "2000 OK backup\n";
+static char OKstore[]   = "2000 OK storage\n";
+static char OKlevel[]   = "2000 OK level\n";
+static char EndBackup[] = "2801 End Backup Job TermCode=%d JobFiles=%u ReadBytes=%" lld " JobBytes=%" lld "\n";
+
 
 /* Forward referenced functions */
 static void backup_cleanup(JCR *jcr, int TermCode, char *since);
@@ -257,19 +259,23 @@ bail_out:
 }
 
 /*
- *  NOTE! This is no longer really needed as the Storage
- *       daemon now passes this information directly
- *       back to us.   
+ * Here we wait for the File daemon to signal termination,
+ *   then we wait for the Storage daemon.  When both
+ *   are done, we return the job status.
  */
 static int wait_for_job_termination(JCR *jcr)
 {
    int32_t n = 0;
    BSOCK *fd = jcr->file_bsock;
+   int fd_ok = FALSE;
 
    jcr->JobStatus = JS_WaitFD;
    /* Wait for Client to terminate */
    while ((n = bget_msg(fd, 0)) > 0 && !job_cancelled(jcr)) {
-      /* get and discard Client output */
+      if (sscanf(fd->msg, EndBackup, &jcr->JobStatus, &jcr->JobFiles,
+         &jcr->ReadBytes, &jcr->JobBytes) == 4) {
+        fd_ok = TRUE;
+      }
    }
    bnet_sig(fd, BNET_TERMINATE);      /* tell Client we are terminating */
    if (n < 0) {
@@ -279,7 +285,11 @@ static int wait_for_job_termination(JCR *jcr)
 
    wait_for_storage_daemon_termination(jcr);
 
-   if (n < 0) {                                    
+   /* Return the first error status we find FD or SD */
+   if (fd_ok && jcr->JobStatus != JS_Terminated) {
+      return jcr->JobStatus;
+   }
+   if (!fd_ok || n < 0) {                                    
       return JS_ErrorTerminated;
    }
    return jcr->SDJobStatus;
@@ -296,7 +306,7 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since)
    char *term_msg;
    int msg_type;
    MEDIA_DBR mr;
-   double kbps;
+   double kbps, compression;
    btime_t RunTime;
 
    Dmsg0(100, "Enter backup_cleanup()\n");
@@ -354,6 +364,12 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since)
       jcr->VolumeName[0] = 0;        /* none */
    }
 
+   if (jcr->ReadBytes == 0) {
+      compression = 0.0;
+   } else {
+      compression = (double)100 - 100.0 * ((double)jcr->JobBytes / (double)jcr->ReadBytes);
+   }
+
    Jmsg(jcr, msg_type, 0, _("%s\n\
 JobId:                  %d\n\
 Job:                    %s\n\
@@ -365,6 +381,7 @@ End time:               %s\n\
 Files Written:          %s\n\
 Bytes Written:          %s\n\
 Rate:                   %.1f KB/s\n\
+Software Compression:   %.1f %%\n\
 Volume names(s):        %s\n\
 Volume Session Id:      %d\n\
 Volume Session Time:    %d\n\
@@ -381,6 +398,7 @@ Termination:            %s\n\n"),
        edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
        edit_uint64_with_commas(jcr->jr.JobBytes, ec2),
        (float)kbps,
+       (float)compression,
        jcr->VolumeName,
        jcr->VolSessionId,
        jcr->VolSessionTime,
index 54303a5d20f81f1487e7b5961a96869bf4f3ac89..70176ff7fefcc95b00c1199e3373fbe8189f75f0 100644 (file)
@@ -256,4 +256,5 @@ void wait_for_storage_daemon_termination(JCR *jcr)
       pthread_cond_timedwait(&jcr->term_wait, &jcr->mutex, &timeout);
    }
    V(jcr->mutex);
+   jcr->JobStatus = jcr->SDJobStatus;
 }
index 8414843c52298aa2b3899c493cd797e8eaf715b9..974bde208e07eff58d67c3cbebaed97cd6cf066c 100644 (file)
@@ -53,7 +53,7 @@ static char OKrestore[]   = "2000 OK restore\n";
 static char OKstore[]     = "2000 OK storage\n";
 static char OKsession[]   = "2000 OK session\n";
 static char OKbootstrap[] = "2000 OK bootstrap\n";
-static char EndJob[]      = "2800 End Job TermCode=%d JobFiles=%u JobBytes=%" lld "\n";
+static char EndRestore[]  = "2800 End Job TermCode=%d JobFiles=%u JobBytes=%" lld "\n";
 
 /* Forward referenced functions */
 static void restore_cleanup(JCR *jcr, int status);
@@ -244,7 +244,7 @@ int do_restore(JCR *jcr)
    Dmsg0(20, "wait for job termination\n");
    while (bget_msg(fd, 0) >  0) {
       Dmsg1(100, "dird<filed: %s\n", fd->msg);
-      if (sscanf(fd->msg, EndJob, &jcr->JobStatus, &jcr->JobFiles,
+      if (sscanf(fd->msg, EndRestore, &jcr->JobStatus, &jcr->JobFiles,
          &jcr->JobBytes) == 3) {
         ok = TRUE;
       }
index 5c1667cce6f616ea5457aa5e22b7ab4235bbde1b..b91a6911f922f14f285c3ebb69b05c1c24f77c95 100644 (file)
@@ -264,6 +264,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr)
 
       msgsave = sd->msg;
       while ((sd->msglen=read(fid, sd->msg, jcr->buf_size)) > 0) {
+        jcr->ReadBytes += sd->msglen; /* count bytes read */
         if (ff_pkt->flags & FO_MD5) {
            MD5Update(&md5c, (unsigned char *)(sd->msg), sd->msglen);
            gotMD5 = 1;
@@ -296,7 +297,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr)
            }
             Dmsg1(130, "Send data to FD len=%d\n", sd->msglen);
 #endif
-           jcr->JobBytes += sd->msglen;
+           jcr->JobBytes += sd->msglen; /* count compressed bytes saved */
            sd->msg = msgsave;        /* restore read buffer */
            continue;
         }
@@ -308,7 +309,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr)
         }
          Dmsg1(130, "Send data to FD len=%d\n", sd->msglen);
 #endif
-        jcr->JobBytes += sd->msglen;
+        jcr->JobBytes += sd->msglen;   /* count bytes saved */
       } /* end while */
 
       if (sd->msglen < 0) {
index be261e2061476134380eefcca8ffce9dd27569eb..cfd78f82bdb910c6fc84679f6b6df8cad5507451 100644 (file)
@@ -108,7 +108,8 @@ static char OKstore[]      = "2000 OK storage\n";
 static char OKjob[]        = "2000 OK Job\n";
 static char OKsetdebug[]   = "2000 OK setdebug=%d\n";
 static char BADjob[]       = "2901 Bad Job\n";
-static char EndJob[]       = "2800 End Job TermCode=%d JobFiles=%u JobBytes=%" lld "\n";
+static char EndRestore[]   = "2800 End Job TermCode=%d JobFiles=%u JobBytes=%" lld "\n";
+static char EndBackup[]    = "2801 End Backup Job TermCode=%d JobFiles=%u ReadBytes=%" lld " JobBytes=%" lld "\n";
 
 /* Responses received from Storage Daemon */
 static char OK_end[]       = "3000 OK end\n";
@@ -582,6 +583,8 @@ cleanup:
       bnet_sig(sd, BNET_TERMINATE);
    }
 
+   bnet_fsend(dir, EndBackup, jcr->JobStatus, jcr->JobFiles, jcr->ReadBytes, jcr->JobBytes);
+
    /* Inform Director that we are done */
    bnet_sig(dir, BNET_TERMINATE);
 
@@ -699,7 +702,7 @@ static int restore_cmd(JCR *jcr)
    /* Inform Storage daemon that we are done */
    bnet_sig(sd, BNET_TERMINATE);
 
-   bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->num_files_examined, jcr->JobBytes);
+   bnet_fsend(dir, EndRestore, jcr->JobStatus, jcr->num_files_examined, jcr->JobBytes);
 
    /* Inform Director that we are done */
    bnet_sig(dir, BNET_TERMINATE);
index fd5c4723633fea6dc1f46c108a962ace76f3d01a..9533105b8a977187af661555a1726bef9f19f917 100644 (file)
@@ -94,6 +94,7 @@ struct s_jcr {
    uint32_t JobFiles;                 /* Number of files written, this job */
    uint32_t JobErrors;                /* */
    uint64_t JobBytes;                 /* Number of bytes processed this job */
+   uint64_t ReadBytes;                /* Bytes read -- before compression */
    uint32_t Errors;                   /* Number of non-fatal errors */
    int JobStatus;                     /* ready, running, blocked, terminated */ 
    int JobType;                       /* backup, restore, verify ... */
index 56b285d7dfafcf185b0831e84e567fb0f84709da..0b7a996eb3af4c5ddff0d111bc875b796cb80177 100644 (file)
@@ -17,7 +17,7 @@ DEBUG=@DEBUG@
 first_rule: all
 dummy:
 
-#
+# bacula-sd
 SVRSRCS = stored.c acquire.c append.c askdir.c authenticate.c \
          block.c dev.c \
          device.c dircmd.c fd_cmds.c fdmsg.c job.c \
@@ -29,31 +29,39 @@ SVROBJS = stored.o acquire.o append.o askdir.o authenticate.o \
          label.o match_bsr.o mount.o parse_bsr.o \
          read.o record.o stored_conf.o
 
-# bpool is deprecated
-#POOLSRCS = bpool.c block.c dev.c device.c askdir.c label.c \
-#          record.c stored_conf.c 
-#POOLOBJS = bpool.o block.o dev.o device.o askdir.o label.o \
-#          record.o stored_conf.o 
-
-#
-TAPESRCS = btape.c block.c dev.c device.c askdir.c label.c \
-          acquire.c mount.c record.c stored_conf.c 
-TAPEOBJS = btape.o block.o dev.o device.o askdir.o label.o \
-          acquire.o mount.o record.o stored_conf.o 
+# btape
+TAPESRCS = btape.c block.c butil.c dev.c device.c label.c \
+          acquire.c mount.c record.c read_record.c \
+          stored_conf.c match_bsr.c parse_bsr.o
+TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o \
+          acquire.o mount.o record.o read_record.o \
+          stored_conf.o match_bsr.o parse_bsr.o
 
+# bls
 BLSOBJS = bls.o block.o device.o dev.o label.o match_bsr.o \
          acquire.o mount.o parse_bsr.o record.o butil.o \
          read_record.o 
 
+# bextract
 BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \
           acquire.o mount.o match_bsr.o parse_bsr.o butil.o \
           read_record.o
 
+# bscan
 SCNOBJS = bscan.o block.o device.o dev.o label.o \
          acquire.o mount.o record.o match_bsr.o parse_bsr.o \
          butil.o read_record.o
 
 
+# bpool is deprecated
+#POOLSRCS = bpool.c block.c dev.c device.c askdir.c label.c \
+#          record.c stored_conf.c 
+#POOLOBJS = bpool.o block.o dev.o device.o askdir.o label.o \
+#          record.o stored_conf.o 
+
+
+
+
 
 # these are the objects that are changed by the .configure process
 EXTRAOBJS = @OBJLIST@
index 00dd57a9873b6bd9c5475fc716982f6172ea45ac..5bab15516b745ecfe522df25355367125b5bac41 100644 (file)
@@ -82,6 +82,7 @@ int main (int argc, char *argv[])
    char line[1000];
    int got_inc = FALSE;
 
+   working_directory = "/tmp";
    my_name_is(argc, argv, "bextract");
    init_msg(NULL, NULL);             /* setup message handler */
 
index 61da289ae277a4c388f19494c95842d4529c5b75..3cac57d2f7b99bace28d1097b713a4f83384e19b 100644 (file)
@@ -78,6 +78,7 @@ int main (int argc, char *argv[])
    FILE *fd;
    char line[1000];
 
+   working_directory = "/tmp";
    my_name_is(argc, argv, "bls");
    init_msg(NULL, NULL);             /* initialize message handler */
 
@@ -392,7 +393,7 @@ int dir_send_job_status(JCR *jcr) {return 1;}
 
 int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
 {
-   fprintf(stderr, "Mount Volume %s on device %s and press return when ready: ",
+   fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
       jcr->VolumeName, dev_name(dev));
    getchar();  
    return 1;
index 91e624bc234f86880787bda993877ceea727165d..8c0df2384d907d598c50925ba519801b3b4c00be 100644 (file)
@@ -59,7 +59,11 @@ static void clearcmd();
 static void wrcmd();
 static void eodcmd();
 static int find_device_res();
-
+static void fillcmd();
+static void unfillcmd();
+static int flush_block(DEV_BLOCK *block);
+static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
+static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
 
 #define CONFIG_FILE "stored.conf"
 
@@ -67,8 +71,20 @@ static char *configfile;
 static char cmd[1000];
 static int signals = TRUE;
 static int default_tape = FALSE;
+static int ok;
+static int stop;
+static uint64_t vol_size;
+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 char *VolumeName = NULL;
 
-static JCR *jcr;
+static JCR *jcr = NULL;
 
 
 static void usage();
@@ -77,6 +93,27 @@ int get_cmd(char *prompt);
 
 static void my_free_jcr(JCR *jcr)
 {
+   if (jcr->pool_name) {
+      free_pool_memory(jcr->pool_name);
+      jcr->pool_name = NULL;
+   }
+   if (jcr->pool_type) {
+      free_pool_memory(jcr->pool_type);
+      jcr->pool_type = NULL;
+   }
+   if (jcr->job_name) {
+      free_pool_memory(jcr->job_name);
+      jcr->job_name = NULL;
+   }
+   if (jcr->client_name) {
+      free_pool_memory(jcr->client_name);
+      jcr->client_name = NULL;
+   }
+   if (jcr->fileset_name) {
+      free_pool_memory(jcr->fileset_name);
+      jcr->fileset_name = NULL;
+   }
+     
    return;
 }
 
@@ -113,7 +150,11 @@ int main(int argc, char *argv[])
 
    printf("Tape block granularity is %d bytes.\n", TAPE_BSIZE);
 
-   while ((ch = getopt(argc, argv, "c:d:st?")) != -1) {
+   working_directory = "/tmp";
+   my_name_is(argc, argv, "btape");
+   init_msg(NULL, NULL);
+
+   while ((ch = getopt(argc, argv, "c:d:stv?")) != -1) {
       switch (ch) {
          case 'c':                    /* specify config file */
            if (configfile != NULL) {
@@ -129,12 +170,16 @@ int main(int argc, char *argv[])
            }
            break;
 
+         case 's':
+           signals = FALSE;
+           break;
+
          case 't':
            default_tape = TRUE;
            break;
 
-         case 's':
-           signals = FALSE;
+         case 'v':
+           verbose++;
            break;
 
          case '?':
@@ -148,8 +193,6 @@ int main(int argc, char *argv[])
    argv += optind;
 
 
-   my_name_is(argc, argv, "btape");
-   init_msg(NULL, NULL);
    
    if (signals) {
       init_signals(terminate_btape);
@@ -188,10 +231,26 @@ int main(int argc, char *argv[])
       }
    }
 
+   /* Setup a "dummy" JCR that should work for most everything */
    jcr = new_jcr(sizeof(JCR), my_free_jcr);
    jcr->VolSessionId = 1;
    jcr->VolSessionTime = (uint32_t)time(NULL);
    jcr->NumVolumes = 1;
+   jcr->pool_name = get_pool_memory(PM_FNAME);
+   strcpy(jcr->pool_name, "Default");
+   jcr->pool_type = get_pool_memory(PM_FNAME);
+   strcpy(jcr->pool_type, "Backup");
+   jcr->job_name = get_pool_memory(PM_FNAME);
+   strcpy(jcr->job_name, "Dummy.Job.Name");
+   jcr->client_name = get_pool_memory(PM_FNAME);
+   strcpy(jcr->client_name, "Dummy.Client.Name");
+   strcpy(jcr->Job, "Dummy.Job");
+   jcr->fileset_name = get_pool_memory(PM_FNAME);
+   strcpy(jcr->fileset_name, "Dummy.fileset.name");
+   jcr->JobId = 1;
+   jcr->JobType = JT_BACKUP;
+   jcr->JobLevel = L_FULL;
+   jcr->JobStatus = JS_Terminated;
 
 
    Dmsg0(200, "Do tape commands\n");
@@ -287,8 +346,12 @@ static void labelcmd()
       return;
    }
 
-   if (!get_cmd("Enter Volume Name: ")) {
-      return;
+   if (VolumeName) {
+      strcpy(cmd, VolumeName);
+   } else {
+      if (!get_cmd("Enter Volume Name: ")) {
+        return;
+      }
    }
         
    if (!(dev->state & ST_OPENED)) {
@@ -609,7 +672,8 @@ I'm going to write one record  in file 0,\n\
    rewindcmd();
    Pmsg0(0, "Now moving to end of media.\n");
    eodcmd();
-   Pmsg2(0, "\nWe should be in file 3. I am at file %d. This is %s\n\n", 
+   Pmsg2(0, "End Append files test.\n\
+We should be in file 3. I am at file %d. This is %s\n\n", 
       dev->file, dev->file == 3 ? "correct!" : "NOT correct!!!!");
 
    Pmsg0(0, "\nNow I am going to attempt to append to the tape.\n");
@@ -618,14 +682,15 @@ I'm going to write one record  in file 0,\n\
 //   weofcmd();
    rewindcmd();
    scancmd();
-   Pmsg0(0, "The above scan should have four files of:\n\
+   Pmsg0(0, "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 respectively.\n\n");
 
 
-   Pmsg0(0, "Append block test.\n\n\
+   Pmsg0(0, "Append block test.\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 block in the first file.\n\n");
+then backspace over the EOF and attempt to append a second\n\
+block in the first file.\n\n");
    rewindcmd();
    wrcmd();
    weofcmd();
@@ -748,6 +813,7 @@ static void scancmd()
       Pmsg0(0, "No device: Use device command.\n");
       return;
    }
+
    blocks = block_size = tot_blocks = 0;
    bytes = 0;
    if (dev->state & ST_EOT) {
@@ -826,6 +892,319 @@ static void statcmd()
 }
 
 
+/* 
+ * First we label the tape, then we fill
+ *  it with data get a new tape and write a few blocks.
+ */                           
+static void fillcmd()
+{
+   DEV_RECORD rec;
+   DEV_BLOCK  *block;
+   char ec1[50];
+   char *p;
+
+   if (!dev) {
+      Pmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+
+   ok = TRUE;
+   stop = FALSE;
+
+   Pmsg0(000, "\n\
+This command simulates Bacula writing to a tape.\n\
+It command requires two blank tapes, which it\n\
+will label and write. It will print a status approximately\n\
+every 322 MB, and write an EOF every 3.2 GB.  When the first tape\n\
+fills, it will ask for a second, and after writing a few \n\
+blocks, it will stop.  Then it will begin re-reading the\n\
+This may take a long time. I.e. hours! ...\n\n");
+
+   get_cmd("Do you wish to continue? (y/n): ");
+   if (cmd[0] != 'y') {
+      Pmsg0(000, "Command aborted.\n");
+      return;
+   }
+
+   VolumeName = "TestVolume1";
+   labelcmd();
+   VolumeName = NULL;
+
+   
+   Dmsg1(20, "Begin append device=%s\n", dev_name(dev));
+
+   block = new_block(dev);
+
+   /* 
+    * Acquire output device for writing.  Note, after acquiring a
+    *  device, we MUST release it, which is done at the end of this
+    *  subroutine.
+    */
+   Dmsg0(100, "just before acquire_device\n");
+   if (!acquire_device_for_append(jcr, dev, block)) {
+      jcr->JobStatus = JS_Cancelled;
+      free_block(block);
+      return;
+   }
+
+   Dmsg0(100, "Just after acquire_device_for_append\n");
+   /*
+    * Write Begin Session Record
+    */
+   if (!write_session_label(jcr, block, SOS_LABEL)) {
+      jcr->JobStatus = JS_Cancelled;
+      Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"),
+        strerror_dev(dev));
+      ok = FALSE;
+   }
+
+   memset(&rec, 0, sizeof(rec));
+   rec.data = get_memory(100000);     /* max record size */
+   /* 
+    * Fill write buffer with random data
+    */
+#define REC_SIZE 32768
+   p = rec.data;
+   for (int i=0; i < REC_SIZE; ) {
+      makeSessionKey(p, NULL, 0);
+      p += 16;
+      i += 16;
+   }
+   rec.data_len = REC_SIZE;
+
+   /* 
+    * Get Data from File daemon, write to device   
+    */
+   jcr->VolFirstFile = 0;
+   time(&jcr->run_time);             /* start counting time for rates */
+   for (file_index = 0; ok && !job_cancelled(jcr); ) {
+      uint64_t *lp;
+      rec.VolSessionId = jcr->VolSessionId;
+      rec.VolSessionTime = jcr->VolSessionTime;
+      rec.FileIndex = ++file_index;
+      rec.Stream = STREAM_FILE_DATA;
+      /* Write file_index at beginning of buffer */
+      lp = (uint64_t *)rec.data;
+      *lp = (uint64_t)file_index;
+
+      Dmsg4(250, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
+        rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream), 
+        rec.data_len);
+       
+      if (!write_record_to_block(block, &rec)) {
+         Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
+                   rec.remainder);
+        if (!flush_block(block)) {
+           return;
+        }
+
+        /* Every 5000 blocks (approx 322MB) report where we are.
+         */
+        if ((block->BlockNumber % 5000) == 0) {
+           now = time(NULL);
+           now -= jcr->run_time;
+           if (now <= 0) {
+              now = 1;
+           }
+           kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
+            Pmsg3(000, "Wrote block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
+              edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs);
+        }
+        /* Every 50000 blocks (approx 3.2MB) write an eof.
+         */
+        if ((block->BlockNumber % 50000) == 0) {
+            Pmsg0(000, "Flush block, write EOF\n");
+           flush_block(block);
+           weof_dev(dev, 1);
+           /* The weof resets the block number */
+        }
+
+        if (block->BlockNumber > 10 && stop) {      /* get out */
+           break;
+        }
+      }
+      if (!ok) {
+         Pmsg0(000, "Not OK\n");
+        break;
+      }
+      jcr->JobBytes += rec.data_len;   /* increment bytes this job */
+      Dmsg4(190, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
+        FI_to_ascii(rec.FileIndex), rec.VolSessionId, 
+        stream_to_ascii(rec.Stream), rec.data_len);
+   }
+   Dmsg0(000, "Write_end_session_label()\n");
+   /* Create Job status for end of session label */
+   if (!job_cancelled(jcr) && ok) {
+      jcr->JobStatus = JS_Terminated;
+   } else if (!ok) {
+      jcr->JobStatus = JS_ErrorTerminated;
+   }
+   if (!write_session_label(jcr, block, EOS_LABEL)) {
+      Pmsg1(000, _("Error writting end session label. ERR=%s\n"), strerror_dev(dev));
+      ok = FALSE;
+   }
+   /* Write out final block of this session */
+   if (!write_block_to_device(jcr, dev, block)) {
+      Pmsg0(000, "Set ok=FALSE after write_block_to_device.\n");
+      ok = FALSE;
+   }
+
+   /* Release the device */
+   if (!release_device(jcr, dev)) {
+      Pmsg0(000, "Error in release_device\n");
+      ok = FALSE;
+   }
+
+   free_block(block);
+   Pmsg0(000, "Done with fill command. Now beginning re-read of tapes...\n");
+
+   unfillcmd();
+}
+
+/*
+ * Read two tapes written by the "fill" command and ensure
+ *  that the data is valid.
+ */
+static void unfillcmd()
+{
+   DEV_BLOCK *block;
+
+   VolBytes = 0;
+   LastBlock = 0;
+   block = new_block(dev);
+
+   dev->capabilities |= CAP_ANONVOLS; /* allow reading any volume */
+   dev->capabilities &= ~CAP_LABEL;   /* don't label anything here */
+
+   end_of_tape = 0;
+   get_cmd("Mount first of two tapes. Press enter when ready: "); 
+   
+   pm_strcpy(&jcr->VolumeName, "TestVolume1");
+   close_dev(dev);
+   dev->state &= ~ST_READ;
+   if (!acquire_device_for_read(jcr, dev, block)) {
+      Pmsg0(000, dev->errmsg);
+      return;
+   }
+
+   time(&jcr->run_time);             /* start counting time for rates */
+   read_records(jcr, dev, record_cb, my_mount_next_read_volume);
+   free_block(block);
+
+   Pmsg0(000, "Done with unfillcmd.\n");
+}
+
+
+static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
+{
+   SESSION_LABEL label;
+   if (rec->FileIndex < 0) {
+      if (verbose > 1) {
+        dump_label_record(dev, rec, 1);
+      }
+      switch (rec->FileIndex) {
+        case PRE_LABEL:
+            Pmsg0(000, "Volume is prelabeled. This tape cannot be scanned.\n");
+           return;
+        case VOL_LABEL:
+           unser_volume_label(dev, rec);
+            Pmsg2(000, "VOL_LABEL: block=%u vol=%s\n", block->BlockNumber, 
+              dev->VolHdr.VolName);
+           break;
+        case SOS_LABEL:
+           unser_session_label(&label, rec);
+            Pmsg1(000, "SOS_LABEL: JobId=%u\n", label.JobId);
+           break;
+        case EOS_LABEL:
+           unser_session_label(&label, rec);
+            Pmsg2(000, "EOS_LABEL: block=%u JobId=%u\n", block->BlockNumber, 
+              label.JobId);
+           break;
+        case EOM_LABEL:
+            Pmsg0(000, "EOM_LABEL:\n");
+           break;
+        case EOT_LABEL:              /* end of all tapes */
+           char ec1[50];
+
+           if (LastBlock != block->BlockNumber) {
+              VolBytes += block->block_len;
+           }
+           LastBlock = block->BlockNumber;
+           now = time(NULL);
+           now -= jcr->run_time;
+           if (now <= 0) {
+              now = 1;
+           }
+           kbs = (double)VolBytes / (1000 * now);
+            Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
+                    edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
+
+            Pmsg0(000, "End of all tapes.\n");
+
+           break;
+        default:
+           break;
+      }
+      return;
+   }
+   if (LastBlock != block->BlockNumber) {
+      VolBytes += block->block_len;
+   }
+   if ((block->BlockNumber != LastBlock) && (block->BlockNumber % 50000) == 0) {
+      char ec1[50];
+      now = time(NULL);
+      now -= jcr->run_time;
+      if (now <= 0) {
+        now = 1;
+      }
+      kbs = (double)VolBytes / (1000 * now);
+      Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
+              edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
+   }
+   LastBlock = block->BlockNumber;
+   if (end_of_tape) {
+      Pmsg1(000, "End of all blocks. Block=%u\n", block->BlockNumber);
+   }
+}
+
+
+
+/*
+ * Write current block to tape regardless of whether or
+ *   not it is full. If the tape fills, attempt to
+ *   acquire another tape.
+ */
+static int flush_block(DEV_BLOCK *block)
+{
+   char ec1[50];
+   lock_device(dev);
+   if (!write_block_to_dev(dev, block)) {
+      Pmsg2(000, "Doing fixup device error. FileIndex=%u Block=%u\n", 
+        (unsigned)file_index, block->BlockNumber);
+      now = time(NULL);
+      now -= jcr->run_time;
+      if (now <= 0) {
+        now = 1;
+      }
+      kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
+      vol_size = dev->VolCatInfo.VolCatBytes;
+      Pmsg2(000, "End of tape. VolumeCapacity=%s. Write rate = %.1f KB/s\n", 
+        edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), kbs);
+      if (!fixup_device_block_write_error(jcr, dev, block)) {
+         Pmsg1(000, _("Cannot fixup device error. %s\n"), strerror_dev(dev));
+        ok = FALSE;
+        unlock_device(dev);
+        return 0;
+      }
+      Pmsg1(000, "Changed tapes. Block=%u\n", block->BlockNumber);
+      stop = 1;                                                    
+      unlock_device(dev);
+      return 1;     /* write one more block to next tape then stop */
+   }
+   unlock_device(dev);
+   return 1;
+}
+
 
 struct cmdstruct { char *key; void (*func)(); char *help; }; 
 static struct cmdstruct commands[] = {
@@ -837,6 +1216,8 @@ static struct cmdstruct commands[] = {
  {"eod",        eodcmd,       "go to end of Bacula data for append"},
  {"test",       testcmd,      "General test Bacula tape functions"},
  {"eom",        eomcmd,       "go to the physical end of medium"},
+ {"fill",       fillcmd,      "fill tape, write onto second volume"},
+ {"unfill",     unfillcmd,    "read filled tape"},
  {"fsf",        fsfcmd,       "forward space a file"},
  {"fsr",        fsrcmd,       "forward space a record"},
  {"help",       helpcmd,      "print this command"},
@@ -932,3 +1313,64 @@ get_cmd(char *prompt)
    quit = 1;
    return 0;
 }
+
+/* Dummies to replace askdir.c */
+int    dir_get_volume_info(JCR *jcr, int writing) { return 1;}
+int    dir_find_next_appendable_volume(JCR *jcr) { return 1;}
+int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
+int    dir_create_jobmedia_record(JCR *jcr) { return 1; }
+int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
+int    dir_send_job_status(JCR *jcr) {return 1;}
+
+
+int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
+{
+   fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
+      jcr->VolumeName, dev_name(dev));
+   getchar();  
+   return 1;
+}
+
+int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev)
+{
+   fprintf(stderr, "Mount next Volume on device %s and press return when ready: ",
+      dev_name(dev));
+   getchar();  
+   VolumeName = "TestVolume2";
+   labelcmd();
+   VolumeName = NULL;
+   return 1;
+}
+
+static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   char ec1[50];
+
+   Pmsg1(000, "End of Volume \"%s\"\n", jcr->VolumeName);
+
+   if (LastBlock != block->BlockNumber) {
+      VolBytes += block->block_len;
+   }
+   LastBlock = block->BlockNumber;
+   now = time(NULL);
+   now -= jcr->run_time;
+   if (now <= 0) {
+      now = 1;
+   }
+   kbs = (double)VolBytes / (1000 * now);
+   Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
+           edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
+
+   if (strcmp(jcr->VolumeName, "TestVolume2") == 0) {
+      end_of_tape = 1;
+      return 0;
+   }
+   pm_strcpy(&jcr->VolumeName, "TestVolume2");
+   close_dev(dev);
+   dev->state &= ~ST_READ; 
+   if (!acquire_device_for_read(jcr, dev, block)) {
+      Pmsg2(0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), jcr->VolumeName);
+      return 0;
+   }
+   return 1;                      /* next volume mounted */
+}
index bf7281b1982c83ec78cb5f5a20312816824be4e7..92a34507ff29e88010f393936ec15f5a1c581d0c 100644 (file)
@@ -453,15 +453,16 @@ void create_session_label(JCR *jcr, DEV_RECORD *rec, int label)
       ser_btime(get_current_btime());
       ser_float64(0);
    } else {
-   get_current_time(&dt);
-   ser_float64(dt.julian_day_number);
-   ser_float64(dt.julian_day_fraction);
+      get_current_time(&dt);
+      ser_float64(dt.julian_day_number);
+      ser_float64(dt.julian_day_fraction);
    }
 
    ser_string(jcr->pool_name);
    ser_string(jcr->pool_type);
    ser_string(jcr->job_name);        /* base Job name */
    ser_string(jcr->client_name);
+
    /* Added in VerNum 10 */
    ser_string(jcr->Job);             /* Unique name of this Job */
    ser_string(jcr->fileset_name);
@@ -476,6 +477,7 @@ void create_session_label(JCR *jcr, DEV_RECORD *rec, int label)
       ser_uint32(jcr->StartFile);
       ser_uint32(jcr->EndFile);
       ser_uint32(jcr->JobErrors);
+
       /* Added in VerNum 11 */
       ser_uint32(jcr->JobStatus);
    }
index c2761e8a41f126c9af10469dace2fc10532b080a..ef79285da55eb12b131a174f00a564f8f12a4f0c 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #define VERSION "1.26"
 #define VSTRING "1"
-#define DATE    "4 October 2002"
-#define LSMDATE "04Oct02"
+#define DATE    "8 October 2002"
+#define LSMDATE "08Oct02"
 
 /* Debug flags */
 #define DEBUG 1