]> git.sur5r.net Git - bacula/bacula/commitdiff
EndBlock fix, enhanced fill in btape, ...
authorKern Sibbald <kern@sibbald.com>
Mon, 16 Dec 2002 09:48:49 +0000 (09:48 +0000)
committerKern Sibbald <kern@sibbald.com>
Mon, 16 Dec 2002 09:48:49 +0000 (09:48 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@240 91ce42f0-d328-0410-95d8-f526ca767f89

17 files changed:
bacula/kernstodo
bacula/src/dird/dird_conf.c
bacula/src/dird/dird_conf.h
bacula/src/dird/restore.c
bacula/src/dird/ua_run.c
bacula/src/jcr.h
bacula/src/lib/util.c
bacula/src/stored/acquire.c
bacula/src/stored/block.c
bacula/src/stored/bscan.c
bacula/src/stored/btape.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/device.c
bacula/src/stored/label.c
bacula/src/stored/mount.c
bacula/src/version.h

index c92cd8e1f58f53ebb66050ca4f67230c9bb326ba..c59909902d5368448a46f12d42d70b9e2e54c61b 100644 (file)
@@ -1,5 +1,5 @@
                  Kern's ToDo List
-                 12 December 2002
+                 16 December 2002
 
 Documentation to do: (a little bit at a time)
 - Document running a test version.
@@ -10,15 +10,11 @@ Testing to do: (painful)
 - that restore options work in FD (mostly done).
 - that console command line options work
 - blocksize recognition code.
-- Test new BSR code (mostly done).
-- Test watchdog child timer code.
-- Test that EndFile/Block are correctly updated at end of tape 
-  (in view of new block reading code).
-
 
 For 1.28 release:
-- Count number of ignored messages in bscan and print when first
-  SOS is found.
+- Implement FileOptions (see end of this document)
+- Make hash table for linked files in findlib/find_one.c:161
+- Make bcopy read through bad tape records.
 - Need a verbose mode in restore, perhaps to bsr.
 - Should we dump a SOS when starting a new tape?
 - bscan without -v is too quiet -- perhaps show jobs.
@@ -27,17 +23,14 @@ For 1.28 release:
 - Figure out how to allow multiple simultaneous file Volumes on
   a single device.
 - Start working on Base jobs.
-- Implement FileOptions (see end of this document)
 - Make sure the MaxVolFiles is fully implemented in SD
 - Flush all the daemon messages at the end of every job.
 - Check if both CatalogFiles and UseCatalog are set to SD.
 - Check if we can increase Bacula FD priorty in Win2000
-- Make bcopy read through bad tape records.
 - Need return status on read_cb() from read_records(). Need multiple
   records -- one per Job, maybe a JCR or some other structure with
   a block and a record.
 
-- Look at hierarchial storage for Bacula.
 - Implement Bacula plugins -- design API
 
 - Work more on how to to a Bacula restore beginning with
@@ -232,6 +225,7 @@ For 1.28 release:
   This could be the output of df; or perhaps some sort of /etc/mtab record.
 
 Longer term to do:
+- Design at hierarchial storage for Bacula.
 - Implement FSM (File System Modules).
 - Identify unchanged or "system" files and save them to a
   special tape thus removing them from the standard 
@@ -628,4 +622,9 @@ Done: (see kernsdone for more)
   to let user know it is working.
 - DateWritten field on tape may be wrong.
 - Ensure that restore of differential jobs works (check SQL).
-
+- Count number of ignored messages in bscan and print when first SOS is found.
+- Test that EndFile/Block are correctly updated at end of tape 
+  (in view of new block reading code).
+- Test watchdog child timer code.
+- Test new BSR code (mostly done).
+    
index 3397cbaebf220618c10f36a2ad9aba53cc4d891a..b9bfd6d9d77ca2154a6a0271d6a65f6068d6cd1e 100644 (file)
@@ -64,6 +64,127 @@ static void store_restore(LEX *lc, struct res_items *item, int index, int pass);
 static void store_jobtype(LEX *lc, struct res_items *item, int index, int pass);
 static void store_level(LEX *lc, struct res_items *item, int index, int pass);
 static void store_replace(LEX *lc, struct res_items *item, int index, int pass);
+static void store_fo(LEX *lc, struct res_items *item, int index, int pass);
+static void store_applyto(LEX *lc, struct res_items *item, int index, int pass);
+
+/* Keywords (RHS) permitted in Job Level records   
+ *
+ *   level_name      level             job_type
+ */
+struct s_jl joblevels[] = {
+   {"Full",          L_FULL,            JT_BACKUP},
+   {"Incremental",   L_INCREMENTAL,     JT_BACKUP},
+   {"Differential",  L_DIFFERENTIAL,    JT_BACKUP},
+   {"Since",         L_SINCE,           JT_BACKUP},
+   {"Catalog",       L_VERIFY_CATALOG,  JT_VERIFY},
+   {"Initcatalog",   L_VERIFY_INIT,     JT_VERIFY},
+   {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG,   JT_VERIFY},
+   {"Data",          L_VERIFY_DATA,     JT_VERIFY},
+   {NULL,           0}
+};
+
+/* Keywords (RHS) permitted in Job type records   
+ *
+ *   type_name      job_type
+ */
+struct s_jt jobtypes[] = {
+   {"backup",        JT_BACKUP},
+   {"admin",         JT_ADMIN},
+   {"verify",        JT_VERIFY},
+   {"restore",       JT_RESTORE},
+   {NULL,           0}
+};
+
+
+/* Keywords (RHS) permitted in Backup and Verify records */
+static struct s_kw BakVerFields[] = {
+   {"client",        'C'},
+   {"fileset",       'F'},
+   {"level",         'L'}, 
+   {NULL,           0}
+};
+
+/* Keywords (RHS) permitted in Restore records */
+static struct s_kw RestoreFields[] = {
+   {"client",        'C'},
+   {"fileset",       'F'},
+   {"jobid",         'J'},            /* JobId to restore */
+   {"where",         'W'},            /* root of restore */
+   {"replace",       'R'},            /* replacement options */
+   {"bootstrap",     'B'},            /* bootstrap file */
+   {NULL,             0}
+};
+
+/* Options permitted in Restore replace= */
+struct s_kw ReplaceOptions[] = {
+   {"always",         REPLACE_ALWAYS},
+   {"ifnewer",        REPLACE_IFNEWER},
+   {"ifolder",        REPLACE_IFOLDER},
+   {"never",          REPLACE_NEVER},
+   {NULL,              0}
+};
+
+
+
+/* Define FileSet KeyWord values */
+
+#define INC_KW_NONE        0
+#define INC_KW_COMPRESSION  1
+#define INC_KW_SIGNATURE    2
+#define INC_KW_ENCRYPTION   3
+#define INC_KW_VERIFY      4
+#define INC_KW_ONEFS       5
+#define INC_KW_RECURSE     6
+#define INC_KW_SPARSE      7
+#define INC_KW_REPLACE     8         /* restore options */
+
+/* Include keywords */
+static struct s_kw FS_option_kw[] = {
+   {"compression", INC_KW_COMPRESSION},
+   {"signature",   INC_KW_SIGNATURE},
+   {"encryption",  INC_KW_ENCRYPTION},
+   {"verify",      INC_KW_VERIFY},
+   {"onefs",       INC_KW_ONEFS},
+   {"recurse",     INC_KW_RECURSE},
+   {"sparse",      INC_KW_SPARSE},
+   {"replace",     INC_KW_REPLACE},
+   {NULL,         0}
+};
+
+/* Options for FileSet keywords */
+
+struct s_fs_opt {
+   char *name;
+   int keyword;
+   char *option;
+};
+
+/* Options permitted for each keyword and resulting value */
+static struct s_fs_opt FS_options[] = {
+   {"md5",      INC_KW_SIGNATURE,    "M"},
+   {"gzip",     INC_KW_COMPRESSION,  "Z6"},
+   {"gzip1",    INC_KW_COMPRESSION,  "Z1"},
+   {"gzip2",    INC_KW_COMPRESSION,  "Z2"},
+   {"gzip3",    INC_KW_COMPRESSION,  "Z3"},
+   {"gzip4",    INC_KW_COMPRESSION,  "Z4"},
+   {"gzip5",    INC_KW_COMPRESSION,  "Z5"},
+   {"gzip6",    INC_KW_COMPRESSION,  "Z6"},
+   {"gzip7",    INC_KW_COMPRESSION,  "Z7"},
+   {"gzip8",    INC_KW_COMPRESSION,  "Z8"},
+   {"gzip9",    INC_KW_COMPRESSION,  "Z9"},
+   {"blowfish", INC_KW_ENCRYPTION,    "B"},   /* ***FIXME*** not implemented */
+   {"3des",     INC_KW_ENCRYPTION,    "3"},   /* ***FIXME*** not implemented */
+   {"yes",      INC_KW_ONEFS,         "0"},
+   {"no",       INC_KW_ONEFS,         "f"},
+   {"yes",      INC_KW_RECURSE,       "0"},
+   {"no",       INC_KW_RECURSE,       "h"},
+   {"yes",      INC_KW_SPARSE,        "s"},
+   {"no",       INC_KW_SPARSE,        "0"},
+   {"always",   INC_KW_REPLACE,       "a"},
+   {"ifnewer",  INC_KW_REPLACE,       "w"},
+   {"never",    INC_KW_REPLACE,       "n"},
+   {NULL,      0,                   0}
+};
 
 
 /* We build the current resource here as we are
@@ -200,6 +321,26 @@ static struct res_items fs_items[] = {
    {NULL,         NULL,       NULL,                  0, 0, 0} 
 };
 
+/*
+ * FileOptions resource (options for Include)
+ *
+ */
+static struct res_items fo_items[] = {
+   {"name",        store_name, ITEM(res_fo.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,  ITEM(res_fo.hdr.desc), 0, 0, 0},
+   {"compression", store_fo,   ITEM(res_fo.opts),     INC_KW_COMPRESSION, 0, 0},
+   {"signature",   store_fo,   ITEM(res_fo.opts),     INC_KW_SIGNATURE, 0, 0},
+   {"encryption",  store_fo,   ITEM(res_fo.opts),     INC_KW_ENCRYPTION, 0, 0},
+   {"onefs",       store_fo,   ITEM(res_fo.opts),     INC_KW_ONEFS, 0, 0},
+   {"recurse",     store_fo,   ITEM(res_fo.opts),     INC_KW_RECURSE, 0, 0},
+   {"sparse",      store_fo,   ITEM(res_fo.opts),     INC_KW_SPARSE, 0, 0},
+   {"replace",     store_fo,   ITEM(res_fo.opts),     INC_KW_REPLACE, 0, 0},
+   {"verify",      store_fo,   ITEM(res_fo.opts),     INC_KW_VERIFY, 0, 0},
+   {"applyto",     store_applyto, ITEM(res_fo.applyto), 0, 0, 0},
+   {NULL,         NULL,       NULL,                  0, 0, 0} 
+};
+
+
 /* Schedule -- see run_conf.c */
 /* Schedule
  *
@@ -282,129 +423,11 @@ struct s_res resources[] = {
    {"pool",          pool_items,  R_POOL,      NULL},
    {"messages",      msgs_items,  R_MSGS,      NULL},
    {"counter",       counter_items, R_COUNTER, NULL},
+   {"fileoptions",   fo_items,    R_FILEOPTIONS, NULL},
    {NULL,           NULL,        0,           NULL}
 };
 
 
-/* Keywords (RHS) permitted in Job Level records   
- *
- *   level_name      level             job_type
- */
-struct s_jl joblevels[] = {
-   {"Full",          L_FULL,            JT_BACKUP},
-   {"Incremental",   L_INCREMENTAL,     JT_BACKUP},
-   {"Differential",  L_DIFFERENTIAL,    JT_BACKUP},
-   {"Level",         L_LEVEL,           JT_BACKUP},
-   {"Since",         L_SINCE,           JT_BACKUP},
-   {"Catalog",       L_VERIFY_CATALOG,  JT_VERIFY},
-   {"Initcatalog",   L_VERIFY_INIT,     JT_VERIFY},
-   {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG,   JT_VERIFY},
-   {"Data",          L_VERIFY_DATA,     JT_VERIFY},
-   {NULL,           0}
-};
-
-/* Keywords (RHS) permitted in Job type records   
- *
- *   type_name      job_type
- */
-struct s_jt jobtypes[] = {
-   {"backup",        JT_BACKUP},
-   {"admin",         JT_ADMIN},
-   {"verify",        JT_VERIFY},
-   {"restore",       JT_RESTORE},
-   {NULL,           0}
-};
-
-
-/* Keywords (RHS) permitted in Backup and Verify records */
-static struct s_kw BakVerFields[] = {
-   {"client",        'C'},
-   {"fileset",       'F'},
-   {"level",         'L'}, 
-   {NULL,           0}
-};
-
-/* Keywords (RHS) permitted in Restore records */
-static struct s_kw RestoreFields[] = {
-   {"client",        'C'},
-   {"fileset",       'F'},
-   {"jobid",         'J'},            /* JobId to restore */
-   {"where",         'W'},            /* root of restore */
-   {"replace",       'R'},            /* replacement options */
-   {"bootstrap",     'B'},            /* bootstrap file */
-   {NULL,             0}
-};
-
-/* Options permitted in Restore replace= */
-struct s_kw ReplaceOptions[] = {
-   {"always",         REPLACE_ALWAYS},
-   {"ifnewer",        REPLACE_IFNEWER},
-   {"ifolder",        REPLACE_IFOLDER},
-   {"never",          REPLACE_NEVER},
-   {NULL,              0}
-};
-
-
-
-/* Define FileSet KeyWord values */
-
-#define INC_KW_NONE        0
-#define INC_KW_COMPRESSION  1
-#define INC_KW_SIGNATURE    2
-#define INC_KW_ENCRYPTION   3
-#define INC_KW_VERIFY      4
-#define INC_KW_ONEFS       5
-#define INC_KW_RECURSE     6
-#define INC_KW_SPARSE      7
-#define INC_KW_REPLACE     8         /* restore options */
-
-/* Include keywords */
-static struct s_kw FS_option_kw[] = {
-   {"compression", INC_KW_COMPRESSION},
-   {"signature",   INC_KW_SIGNATURE},
-   {"encryption",  INC_KW_ENCRYPTION},
-   {"verify",      INC_KW_VERIFY},
-   {"onefs",       INC_KW_ONEFS},
-   {"recurse",     INC_KW_RECURSE},
-   {"sparse",      INC_KW_SPARSE},
-   {"replace",     INC_KW_REPLACE},
-   {NULL,         0}
-};
-
-/* Options for FileSet keywords */
-
-struct s_fs_opt {
-   char *name;
-   int keyword;
-   char *option;
-};
-
-/* Options permitted for each keyword and resulting value */
-static struct s_fs_opt FS_options[] = {
-   {"md5",      INC_KW_SIGNATURE,    "M"},
-   {"gzip",     INC_KW_COMPRESSION,  "Z6"},
-   {"gzip1",    INC_KW_COMPRESSION,  "Z1"},
-   {"gzip2",    INC_KW_COMPRESSION,  "Z2"},
-   {"gzip3",    INC_KW_COMPRESSION,  "Z3"},
-   {"gzip4",    INC_KW_COMPRESSION,  "Z4"},
-   {"gzip5",    INC_KW_COMPRESSION,  "Z5"},
-   {"gzip6",    INC_KW_COMPRESSION,  "Z6"},
-   {"gzip7",    INC_KW_COMPRESSION,  "Z7"},
-   {"gzip8",    INC_KW_COMPRESSION,  "Z8"},
-   {"gzip9",    INC_KW_COMPRESSION,  "Z9"},
-   {"blowfish", INC_KW_ENCRYPTION,    "B"},   /* ***FIXME*** not implemented */
-   {"3des",     INC_KW_ENCRYPTION,    "3"},   /* ***FIXME*** not implemented */
-   {"yes",      INC_KW_ONEFS,         "0"},
-   {"no",       INC_KW_ONEFS,         "f"},
-   {"yes",      INC_KW_RECURSE,       "0"},
-   {"no",       INC_KW_RECURSE,       "h"},
-   {"yes",      INC_KW_SPARSE,        "s"},
-   {"no",       INC_KW_SPARSE,        "0"},
-   {"always",   INC_KW_REPLACE,       "a"},
-   {"ifnewer",  INC_KW_REPLACE,       "w"},
-   {"never",    INC_KW_REPLACE,       "n"},
-   {NULL,      0,                   0}
-};
 
 char *level_to_str(int level)
 {
@@ -1359,3 +1382,60 @@ static void store_inc(LEX *lc, struct res_items *item, int index, int pass)
    lc->options = options;
    set_bit(index, res_all.hdr.item_present);
 }
+
+/* Store FileOptions */
+static void store_fo(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token, i;
+   int options = lc->options;
+   int keyword;
+   char inc_opts[100];
+   int inc_opts_len;
+
+   lc->options |= LOPT_NO_IDENT;      /* make spaces significant */
+
+   /* Get include options */
+   strcpy(inc_opts, "0");             /* set no options */
+   while ((token=lex_get_token(lc, T_ALL)) != T_BOB) {
+      keyword = INC_KW_NONE;
+      for (i=0; FS_option_kw[i].name; i++) {
+        if (strcasecmp(lc->str, FS_option_kw[i].name) == 0) {
+           keyword = FS_option_kw[i].token;
+           break;
+        }
+      }
+      if (keyword == INC_KW_NONE) {
+         scan_err1(lc, "Expected a FileSet keyword, got: %s", lc->str);
+      }
+      /* Option keyword should be following by = <option> */
+      if ((token=lex_get_token(lc, T_ALL)) != T_EQUALS) {
+         scan_err1(lc, "expected an = following keyword, got: %s", lc->str);
+      }
+      scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts));
+      if (token == T_BOB) {
+        break;
+      }
+   }
+   strcat(inc_opts, " ");             /* add field separator */
+   inc_opts_len = strlen(inc_opts);
+
+
+   if (pass == 1) {
+      if (!res_all.res_fs.have_MD5) {
+        MD5Init(&res_all.res_fs.md5c);
+        res_all.res_fs.have_MD5 = TRUE;
+      }
+   } else { /* pass 2 */
+      while (lex_get_token(lc, T_ALL) != T_EOB) 
+        {}
+   }
+   scan_to_eol(lc);
+   lc->options = options;
+   set_bit(index, res_all.hdr.item_present);
+}
+
+/* Store FileOptions */
+static void store_applyto(LEX *lc, struct res_items *item, int index, int pass)
+{
+   scan_to_eol(lc);
+}
index a8fa1e449d2fc1170c5d6f6e54f28f3007cd3da9..570a3251af2a52c80bb4b57c6dbbf4298bfebe64 100644 (file)
 /*
  * Resource codes -- they must be sequential for indexing   
  */
-#define R_FIRST                       1001
-
-#define R_DIRECTOR                    1001
-#define R_CLIENT                      1002
-#define R_JOB                         1003
-#define R_STORAGE                     1004
-#define R_CATALOG                     1005
-#define R_SCHEDULE                    1006
-#define R_FILESET                     1007
-#define R_GROUP                       1008
-#define R_POOL                        1009
-#define R_MSGS                        1010
-#define R_COUNTER                     1011
-
-#define R_LAST                        R_COUNTER
+#define R_FIRST                      1001
+
+#define R_DIRECTOR                   1001
+#define R_CLIENT                     1002
+#define R_JOB                        1003
+#define R_STORAGE                    1004
+#define R_CATALOG                    1005
+#define R_SCHEDULE                   1006
+#define R_FILESET                    1007
+#define R_GROUP                      1008
+#define R_POOL                       1009
+#define R_MSGS                       1010
+#define R_COUNTER                    1011
+#define R_FILEOPTIONS                1012
+
+#define R_LAST                       R_FILEOPTIONS
 
 /*
  * Some resource attributes
  */
-#define R_NAME                        1020
-#define R_ADDRESS                     1021
-#define R_PASSWORD                    1022
-#define R_TYPE                        1023
-#define R_BACKUP                      1024
+#define R_NAME                       1020
+#define R_ADDRESS                    1021
+#define R_PASSWORD                   1022
+#define R_TYPE                       1023
+#define R_BACKUP                     1024
 
 
 /* Used for certain KeyWord tables */
-struct s_kw {       
+struct s_kw {      
    char *name;
-   int token;   
+   int token;  
 };
 
 /* Job Level keyword structure */
 struct s_jl {
-   char *level_name;                  /* level keyword */
-   int  level;                        /* level */
-   int  job_type;                     /* JobType permitting this level */
+   char *level_name;                 /* level keyword */
+   int level;                        /* level */
+   int job_type;                     /* JobType permitting this level */
 };
 
 /* Job Type keyword structure */
@@ -78,22 +79,22 @@ struct s_jt {
 /* Definition of the contents of each Resource */
 
 /* 
- *   Director Resource  
+ *   Director Resource 
  *
  */
 struct s_res_dir {
-   RES   hdr;
-   int   DIRport;                     /* where we listen -- UA port server port */
-   char *DIRaddr;                     /* bind address */
-   char *password;                    /* Password for UA access */
-   char *query_file;                  /* SQL query file */
-   char *working_directory;           /* WorkingDirectory */
-   char *pid_directory;               /* PidDirectory */
-   char *subsys_directory;            /* SubsysDirectory */
+   RES  hdr;
+   int  DIRport;                     /* where we listen -- UA port server port */
+   char *DIRaddr;                    /* bind address */
+   char *password;                   /* Password for UA access */
+   char *query_file;                 /* SQL query file */
+   char *working_directory;          /* WorkingDirectory */
+   char *pid_directory;              /* PidDirectory */
+   char *subsys_directory;           /* SubsysDirectory */
    struct s_res_msgs *messages;       /* Daemon message handler */
-   int   MaxConcurrentJobs;
-   utime_t FDConnectTimeout;          /* timeout for connect in seconds */
-   utime_t SDConnectTimeout;          /* timeout in seconds */
+   int  MaxConcurrentJobs;
+   utime_t FDConnectTimeout;         /* timeout for connect in seconds */
+   utime_t SDConnectTimeout;         /* timeout in seconds */
 };
 typedef struct s_res_dir DIRRES;
 
@@ -102,12 +103,12 @@ typedef struct s_res_dir DIRRES;
  *
  */
 struct s_res_client {
-   RES   hdr;
+   RES  hdr;
 
-   int   FDport;                      /* Where File daemon listens */
-   int   AutoPrune;                   /* Do automatic pruning? */
-   utime_t FileRetention;             /* file retention period in seconds */
-   utime_t JobRetention;              /* job retention period in seconds */
+   int  FDport;                      /* Where File daemon listens */
+   int  AutoPrune;                   /* Do automatic pruning? */
+   utime_t FileRetention;            /* file retention period in seconds */
+   utime_t JobRetention;             /* job retention period in seconds */
    char *address;
    char *password;
    struct s_res_cat    *catalog;       /* Catalog resource */
@@ -119,15 +120,15 @@ typedef struct s_res_client CLIENT;
  * 
  */
 struct s_res_store {
-   RES   hdr;
+   RES  hdr;
 
-   int   SDport;                      /* port where Directors connect */
-   int   SDDport;                     /* data port for File daemon */
+   int  SDport;                      /* port where Directors connect */
+   int  SDDport;                     /* data port for File daemon */
    char *address;
    char *password;
    char *media_type;
    char *dev_name;   
-   int  autochanger;                  /* set if autochanger */
+   int autochanger;                  /* set if autochanger */
 };
 typedef struct s_res_store STORE;
 
@@ -136,9 +137,9 @@ typedef struct s_res_store STORE;
  *
  */
 struct s_res_cat {
-   RES   hdr;
+   RES  hdr;
 
-   int   DBport;                      /* Port -- not yet implemented */
+   int  DBport;                      /* Port -- not yet implemented */
    char *address;
    char *db_password;
    char *db_user;
@@ -151,30 +152,30 @@ typedef struct s_res_cat CAT;
  *
  */
 struct s_res_job {
-   RES   hdr;
-
-   int   JobType;                     /* job type (backup, verify, restore */
-   int   level;                       /* default backup/verify level */
-   int   RestoreJobId;                /* What -- JobId to restore */
-   char *RestoreWhere;                /* Where on disk to restore -- directory */
-   char *RestoreBootstrap;            /* Bootstrap file */
-   char *RunBeforeJob;                /* Run program before Job */
-   char *RunAfterJob;                 /* Run program after Job */
-   char *WriteBootstrap;              /* Where to write bootstrap Job updates */
-   int   replace;                     /* How (overwrite, ..) */
-   utime_t MaxRunTime;                /* max run time in seconds */
-   utime_t MaxStartDelay;             /* max start delay in seconds */
-   int PruneJobs;                     /* Force pruning of Jobs */
-   int PruneFiles;                    /* Force pruning of Files */
-   int PruneVolumes;                  /* Force pruning of Volumes */
-   int SpoolAttributes;               /* Set to spool attributes in SD */
+   RES  hdr;
+
+   int  JobType;                     /* job type (backup, verify, restore */
+   int  level;                       /* default backup/verify level */
+   int  RestoreJobId;                /* What -- JobId to restore */
+   char *RestoreWhere;               /* Where on disk to restore -- directory */
+   char *RestoreBootstrap;           /* Bootstrap file */
+   char *RunBeforeJob;               /* Run program before Job */
+   char *RunAfterJob;                /* Run program after Job */
+   char *WriteBootstrap;             /* Where to write bootstrap Job updates */
+   int  replace;                     /* How (overwrite, ..) */
+   utime_t MaxRunTime;               /* max run time in seconds */
+   utime_t MaxStartDelay;            /* max start delay in seconds */
+   int PruneJobs;                    /* Force pruning of Jobs */
+   int PruneFiles;                   /* Force pruning of Files */
+   int PruneVolumes;                 /* Force pruning of Volumes */
+   int SpoolAttributes;              /* Set to spool attributes in SD */
 
    struct s_res_msgs   *messages;     /* How and where to send messages */
    struct s_res_sch    *schedule;     /* When -- Automatic schedule */
    struct s_res_client *client;       /* Who to backup */
    struct s_res_fs     *fileset;      /* What to backup -- Fileset */
    struct s_res_store  *storage;      /* Where is device -- Storage daemon */
-   struct s_res_pool   *pool;         /* Where is media -- Media Pool */
+   struct s_res_pool   *pool;        /* Where is media -- Media Pool */
 };
 typedef struct s_res_job JOB;
 
@@ -183,7 +184,7 @@ typedef struct s_res_job JOB;
  *
  */
 struct s_res_fs {
-   RES   hdr;
+   RES  hdr;
 
    char **include_array;
    int num_includes;
@@ -191,11 +192,22 @@ struct s_res_fs {
    char **exclude_array;
    int num_excludes;
    int exclude_size;
-   int have_MD5;                      /* set if MD5 initialized */
-   struct MD5Context md5c;            /* MD5 of include/exclude */
-   char MD5[50];                      /* base 64 representation of MD5 */
+   int have_MD5;                     /* set if MD5 initialized */
+   struct MD5Context md5c;           /* MD5 of include/exclude */
+   char MD5[50];                     /* base 64 representation of MD5 */
 };
 typedef struct s_res_fs FILESET;
+
+/*
+ * FileOptions Resource (options for Includes)
+ */
+struct s_res_fo {
+   RES hdr;
+
+   char opts[50];                    /* Options string */
+   struct s_applyto *applyto;        /* applyto strings */
+}; 
+typedef struct s_res_fo FILEOPTIONS;
  
 
 /* 
@@ -203,7 +215,7 @@ typedef struct s_res_fs FILESET;
  *
  */
 struct s_res_sch {
-   RES   hdr;
+   RES  hdr;
 
    struct s_run *run;
 };
@@ -214,7 +226,7 @@ typedef struct s_res_sch SCHED;
  *
  */
 struct s_res_group {
-   RES   hdr;
+   RES  hdr;
 };
 typedef struct s_res_group GROUP;
 
@@ -222,12 +234,12 @@ typedef struct s_res_group GROUP;
  *   Counter Resource
  */
 struct s_res_counter {
-   RES   hdr;
+   RES  hdr;
 
-   int32_t MinValue;                  /* Minimum value */
-   int32_t MaxValue;                  /* Maximum value */
-   int     Global;                    /* global/local */
-   char  *WrapCounter;                /* Wrap counter name */
+   int32_t MinValue;                 /* Minimum value */
+   int32_t MaxValue;                 /* Maximum value */
+   int    Global;                    /* global/local */
+   char  *WrapCounter;               /* Wrap counter name */
 };
 typedef struct s_res_counter COUNTER;
 
@@ -236,23 +248,23 @@ typedef struct s_res_counter COUNTER;
  *
  */
 struct s_res_pool {
-   RES   hdr;
+   RES  hdr;
 
    struct s_res_counter counter;      /* Counter resources */
-   char *pool_type;                   /* Pool type */
-   char *label_format;                /* Label format string */
-   int   use_catalog;                 /* maintain catalog for media */
-   int   catalog_files;               /* maintain file entries in catalog */
-   int   use_volume_once;             /* write on volume only once */
-   int   accept_any_volume;           /* accept any volume */
-   uint32_t max_volumes;              /* max number of volumes */
-   utime_t VolRetention;              /* volume retention period in seconds */
-   utime_t VolUseDuration;            /* duration volume can be used */
-   uint32_t MaxVolJobs;               /* Maximum jobs on the Volume */
-   uint32_t MaxVolFiles;              /* Maximum files on the Volume */
-   uint64_t MaxVolBytes;              /* Maximum bytes on the Volume */
-   int   AutoPrune;                   /* default for pool auto prune */
-   int   Recycle;                     /* default for media recycle yes/no */
+   char *pool_type;                  /* Pool type */
+   char *label_format;               /* Label format string */
+   int  use_catalog;                 /* maintain catalog for media */
+   int  catalog_files;               /* maintain file entries in catalog */
+   int  use_volume_once;             /* write on volume only once */
+   int  accept_any_volume;           /* accept any volume */
+   uint32_t max_volumes;             /* max number of volumes */
+   utime_t VolRetention;             /* volume retention period in seconds */
+   utime_t VolUseDuration;           /* duration volume can be used */
+   uint32_t MaxVolJobs;              /* Maximum jobs on the Volume */
+   uint32_t MaxVolFiles;             /* Maximum files on the Volume */
+   uint64_t MaxVolBytes;             /* Maximum bytes on the Volume */
+   int  AutoPrune;                   /* default for pool auto prune */
+   int  Recycle;                     /* default for media recycle yes/no */
 };
 typedef struct s_res_pool POOL;
 
@@ -261,17 +273,18 @@ typedef struct s_res_pool POOL;
  * resource structure definitions.
  */
 union u_res {
-   struct s_res_dir     res_dir;
-   struct s_res_client  res_client;
-   struct s_res_store   res_store;
-   struct s_res_cat     res_cat;
-   struct s_res_job     res_job;
-   struct s_res_fs      res_fs;
-   struct s_res_sch     res_sch;
-   struct s_res_group   res_group;
-   struct s_res_pool    res_pool;
-   struct s_res_msgs    res_msgs;
+   struct s_res_dir    res_dir;
+   struct s_res_client res_client;
+   struct s_res_store  res_store;
+   struct s_res_cat    res_cat;
+   struct s_res_job    res_job;
+   struct s_res_fs     res_fs;
+   struct s_res_sch    res_sch;
+   struct s_res_group  res_group;
+   struct s_res_pool   res_pool;
+   struct s_res_msgs   res_msgs;
    struct s_res_counter res_counter;
+   struct s_res_fo     res_fo;
    RES hdr;
 };
 
@@ -280,17 +293,17 @@ typedef union u_res URES;
 
 /* Run structure contained in Schedule Resource */
 struct s_run {
-   struct s_run *next;                /* points to next run record */
-   int level;                         /* level override */
+   struct s_run *next;               /* points to next run record */
+   int level;                        /* level override */
    int job_type;  
-   POOL *pool;                        /* Pool override */
-   STORE *storage;                    /* Storage override */
-   MSGS *msgs;                        /* Messages override */
+   POOL *pool;                       /* Pool override */
+   STORE *storage;                   /* Storage override */
+   MSGS *msgs;                       /* Messages override */
    char *since;
    int level_no;
-   int minute;                        /* minute to run job */
-   time_t last_run;                   /* last time run */
-   time_t next_run;                   /* next time to run */
+   int minute;                       /* minute to run job */
+   time_t last_run;                  /* last time run */
+   time_t next_run;                  /* next time to run */
    char hour[nbytes_for_bits(24)];    /* bit set for each hour */
    char mday[nbytes_for_bits(31)];    /* bit set for each day of month */
    char month[nbytes_for_bits(12)];   /* bit set for each month */
index f1d132aedbc8f20d7604c7c0062e7d8a2b3f816d..e11d110808f32fd86215cb5101929d4373e9a028 100644 (file)
@@ -330,7 +330,7 @@ Termination:            %s\n\n"),
        jcr->client->hdr.name,
        sdt,
        edt,
-       edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
+       edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec1),
        edit_uint64_with_commas(jcr->jr.JobBytes, ec2),
        (float)kbps,
        term_msg);
index 76fad8633636b5bf9c50677535a969ed6370a9a0..b89f4701995988998835d476efa0bd76592ceaee 100644 (file)
@@ -411,7 +411,6 @@ JobId:      %s\n"),
             add_prompt(ua, _("Full"));
             add_prompt(ua, _("Incremental"));
             add_prompt(ua, _("Differential"));
-            add_prompt(ua, _("Level"));
             add_prompt(ua, _("Since"));
             switch (do_prompt(ua, _("Select level"), NULL, 0)) {
            case 0:
@@ -424,9 +423,6 @@ JobId:      %s\n"),
               jcr->JobLevel = L_DIFFERENTIAL;
               break;
            case 3:
-              jcr->JobLevel = L_LEVEL;
-              break;
-           case 4:
               jcr->JobLevel = L_SINCE;
               break;
            default:
index 01fb04b712079e45d0eb361b141643c44c7d163b..2fa0eebe45b2b748fc697a0d285d7b122c189c37 100644 (file)
@@ -36,7 +36,6 @@
 #define L_FULL                   'F'
 #define L_INCREMENTAL            'I'  /* since last backup */
 #define L_DIFFERENTIAL           'D'  /* since last full backup */
-#define L_LEVEL                  'L'
 #define L_SINCE                  'S'
 #define L_VERIFY_CATALOG         'C'  /* verify from catalog */
 #define L_VERIFY_INIT            'V'  /* verify save (init DB) */
index 2c6940aa91994af6929be0c4907e500241d7771e..36b8e84b9d86d00776e12ac850a133651f7bb0a1 100644 (file)
@@ -333,9 +333,6 @@ char *job_level_to_str(int level)
    case L_DIFFERENTIAL:
       str = _("Differential");
       break;
-   case L_LEVEL:
-      str = _("Level");
-      break;
    case L_SINCE:
       str = _("Since");
       break;
index 59418bc86ad4d97c6d24ba3acd765477aa6b6c6e..3dffef301c60742f43567e91e177e68d3e32a3f5 100644 (file)
@@ -236,11 +236,19 @@ int release_device(JCR *jcr, DEVICE *dev)
 
    } else if (dev->num_writers > 0) {
       dev->num_writers--;
+      if (dev->state & ST_TAPE) {
+        jcr->EndBlock = dev->EndBlock;
+        jcr->EndFile  = dev->EndFile;
+         Dmsg2(000, "Release device: EndFile=%u EndBlock=%u\n", jcr->EndFile, jcr->EndBlock);
+      } else {
+        jcr->EndBlock = (uint32_t)dev->file_addr;
+        jcr->EndFile = (uint32_t)(dev->file_addr >> 32);
+      }
       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
       if (dev->num_writers == 0) {
-        weof_dev(dev, 1);
          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
         dir_create_jobmedia_record(jcr);
+        weof_dev(dev, 1);
         dev->VolCatInfo.VolCatFiles++;             /* increment number of files */
         dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
         /* Note! do volume update before close, which zaps VolCatInfo */
index 17dd3b7f70258d6d71931c61c9bfd78ff77804ab..ce3c9234895559606989ca5c4ae3fe3fd0b68e41 100644 (file)
@@ -190,7 +190,7 @@ static int unser_block_header(DEVICE *dev, DEV_BLOCK *block)
    char Id[BLKHDR_ID_LENGTH+1];
    uint32_t CheckSum, BlockCheckSum;
    uint32_t block_len;
-   uint32_t EndBlock;
+   uint32_t block_end;
    uint32_t BlockNumber;
    int bhl;
 
@@ -241,11 +241,11 @@ static int unser_block_header(DEVICE *dev, DEV_BLOCK *block)
    Dmsg1(190, "unser_block_header block_len=%d\n", block_len);
    /* Find end of block or end of buffer whichever is smaller */
    if (block_len > block->read_len) {
-      EndBlock = block->read_len;
+      block_end = block->read_len;
    } else {
-      EndBlock = block_len;
+      block_end = block_len;
    }
-   block->binbuf = EndBlock - bhl;
+   block->binbuf = block_end - bhl;
    block->block_len = block_len;
    block->BlockNumber = BlockNumber;
    Dmsg3(190, "Read binbuf = %d %d block_len=%d\n", block->binbuf,
@@ -355,6 +355,8 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
            edit_uint64(dev->VolCatInfo.VolCatMaxBytes, ed1),  dev->dev_name);
       }
       block->failed_write = TRUE;
+      dev->EndBlock = dev->block_num;
+      dev->EndFile  = dev->file;
       weof_dev(dev, 1);              /* end the tape */
       weof_dev(dev, 1);              /* write second eof */
       return 0;
@@ -383,6 +385,8 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       Mmsg4(&dev->errmsg, _("Write error on device %s. Write of %u bytes got %d. ERR=%s.\n"), 
         dev->dev_name, wlen, stat, strerror(dev->dev_errno));
       block->failed_write = TRUE;
+      dev->EndBlock = dev->block_num;
+      dev->EndFile  = dev->file;
       weof_dev(dev, 1);              /* end the tape */
       weof_dev(dev, 1);              /* write second eof */
        
@@ -396,11 +400,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
        *   correct.
        */
       if (dev->state & ST_TAPE && dev->capabilities & CAP_BSR) {
-        uint32_t file, block_num;
 
-        file = dev->file;
-        block_num = dev->block_num;
-        
         /* Now back up over what we wrote and read the last block */
         if (bsf_dev(dev, 1) != 0 || bsf_dev(dev, 1) != 0) {
            ok = FALSE;
@@ -427,8 +427,6 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
            }
            free_block(lblock);
         }
-        dev->file = file;
-        dev->block_num = block_num;
       }
 #endif
       return 0;
@@ -436,6 +434,8 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    dev->VolCatInfo.VolCatBytes += block->binbuf;
    dev->VolCatInfo.VolCatBlocks++;   
    dev->file_addr += wlen;
+   dev->EndBlock = dev->block_num;
+   dev->EndFile  = dev->file;
 
    /* Limit maximum File size on volume to user specified value */
    if (dev->state & ST_TAPE) {
index 075505db5aa4ea736eb7dfc5db701ceb032b2491..bcf9f223fb269ad3380e9c653836ad4853eba892 100644 (file)
@@ -84,6 +84,7 @@ static int verbose = 0;
 static int update_db = 0;
 static int update_vol_info = 0;
 static int list_records = 0;
+static int ignored_msgs = 0;
 
 #define CONFIG_FILE "bacula-sd.conf"
 char *configfile;
@@ -327,6 +328,11 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
            break;
         case SOS_LABEL:
            mr.VolJobs++;
+           if (ignored_msgs > 0) {
+               Pmsg1(000, _("%d \"errors\" ignored before first Start of Session record.\n"), 
+                    ignored_msgs);
+              ignored_msgs = 0;
+           }
            unser_session_label(&label, rec);
            memset(&jr, 0, sizeof(jr));
            jr.JobId = label.JobId;
@@ -511,6 +517,8 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         if (mr.VolJobs > 0) {
             Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"),
                         rec->VolSessionId, rec->VolSessionTime);
+        } else {
+           ignored_msgs++;
         }
         return;
       }
@@ -532,6 +540,8 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         if (mr.VolJobs > 0) {
             Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for File Data record.\n"),
                         rec->VolSessionId, rec->VolSessionTime);
+        } else {
+           ignored_msgs++;
         }
         return;
       }
@@ -544,6 +554,8 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         if (mr.VolJobs > 0) {
             Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Sparse Data record.\n"),
                         rec->VolSessionId, rec->VolSessionTime);
+        } else {
+           ignored_msgs++;
         }
         return;
       }
@@ -556,6 +568,8 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         if (mr.VolJobs > 0) {
             Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for GZIP Data record.\n"),
                         rec->VolSessionId, rec->VolSessionTime);
+        } else {
+           ignored_msgs++;
         }
         return;
       }
@@ -568,6 +582,8 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         if (mr.VolJobs > 0) {
             Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Sparse GZIP Data record.\n"),
                         rec->VolSessionId, rec->VolSessionTime);
+        } else {
+           ignored_msgs++;
         }
         return;
       }
@@ -960,8 +976,8 @@ static int create_jobmedia_record(B_DB *db, JCR *mjcr)
    JOBMEDIA_DBR jmr;
 
    if (dev->state & ST_TAPE) {
-      mjcr->EndBlock = dev->block_num;
-      mjcr->EndFile = dev->file;
+      mjcr->EndBlock = dev->EndBlock;
+      mjcr->EndFile  = dev->EndFile;
    } else {
       mjcr->EndBlock = (uint32_t)dev->file_addr;
       mjcr->EndFile = (uint32_t)(dev->file_addr >> 32);
@@ -1005,6 +1021,8 @@ static int update_MD5_record(B_DB *db, char *MD5buf, DEV_RECORD *rec)
       if (mr.VolJobs > 0) {
          Pmsg2(000, _("Could not find SessId=%d SessTime=%d for MD5 record.\n"),
                      rec->VolSessionId, rec->VolSessionTime);
+      } else {
+        ignored_msgs++;
       }
       return 0;
    }
@@ -1075,8 +1093,8 @@ int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
          Pmsg1(000, "create JobMedia for Job %s\n", mjcr->Job);
       }
       if (dev->state & ST_TAPE) {
-        mjcr->EndBlock = dev->block_num;
-        mjcr->EndFile = dev->file;
+        mjcr->EndBlock = dev->EndBlock;
+        mjcr->EndFile = dev->EndFile;
       } else {
         mjcr->EndBlock = (uint32_t)dev->file_addr;
         mjcr->StartBlock = (uint32_t)(dev->file_addr >> 32);
index d074ccd849633d1906fd52ab3d7f15af78910208..ce91e5cd45766097af0dde53c5d13a67c355882d 100644 (file)
@@ -87,6 +87,11 @@ static uint32_t eot_block;
 static uint32_t eot_block_len;
 static uint32_t eot_FileIndex;
 static int dumped = 0;
+static DEV_BLOCK *last_block = NULL;
+static DEV_BLOCK *this_block = NULL;
+static uint32_t last_file = 0;
+static uint32_t last_block_num = 0;
+static int simple = TRUE;
 
 static char *VolumeName = NULL;
 
@@ -252,6 +257,13 @@ static void terminate_btape(int stat)
       free_bsr(bsr);
    }
 
+   if (last_block) {
+      free_block(last_block);
+   }
+   if (this_block) {
+      free_block(this_block);
+   }
+
    term_msg();
    close_memory_pool();              /* free memory in pool */
 
@@ -680,19 +692,8 @@ respectively each with 64,448 bytes.\n\n"));
    return 1;
 }
 
-
-/* 
- * This is a general test of Bacula's functions
- *   needed to read and write the tape.
- */
-static void testcmd()
+void append_block_test()  
 {
-   re_read_block_test();
-
-   if (!append_test()) {
-      return;
-   }
-
    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\
@@ -716,17 +717,35 @@ block in the first file.\n\n");
 }
 
 
-static void fsfcmd()
+
+/* 
+ * This is a general test of Bacula's functions
+ *   needed to read and write the tape.
+ */
+static void testcmd()
 {
-   int stat;
+   re_read_block_test();
+
+   if (!append_test()) {
+      return;
+   }
+
+   append_block_test();
+
+
+}
 
-   if ((stat=fsf_dev(dev, 1)) < 0) {
-      Pmsg2(0, "Bad status from fsf %d. ERR=%s\n", stat, strerror_dev(dev));
+/* Forward space a file */
+static void fsfcmd()
+{
+   if (!fsf_dev(dev, 1)) {
+      Pmsg1(0, "Bad status from fsf. ERR=%s\n", strerror_dev(dev));
       return;
    }
    Pmsg0(0, "Forward spaced one file.\n");
 }
 
+/* Forward space a record */
 static void fsrcmd()
 {
    int stat;
@@ -738,6 +757,7 @@ static void fsrcmd()
    Pmsg0(0, "Forward spaced one record.\n");
 }
 
+/* DEPRECATED DO NOT USE */
 static void rdcmd()
 {
 #ifdef xxxxx
@@ -980,19 +1000,30 @@ static void fillcmd()
    char *p;
 
    ok = TRUE;
-   stop = FALSE;
+   stop = 0;
 
    Pmsg0(000, "\n\
 This command simulates Bacula writing to a tape.\n\
-It command requires two blank tapes, which it\n\
+It requires either one or 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\
+every 322 MB, and write an EOF every 3.2 GB.  If you have\n\
+selected the simple test option, after writing the first tape\n\
+it will rewind it and re-read the last block written.\n\
+If you have selected the multiple tape test, 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("Insert a blank tape then answer. Do you wish to continue? (y/n): ");
-   if (cmd[0] != 'y') {
+   get_cmd("Insert a blank tape then indicate if you want\n"
+           "to run the simplified test (s) with one tape or\n"
+           "the complete multiple tape (m) test: (s/m) ");
+   if (cmd[0] == 's') {
+      Pmsg0(-1, "Simple test (single tape) selected.\n");
+      simple = TRUE;
+   } else if (cmd[0] == 'm') {
+      Pmsg0(-1, "Complete multiple tape test selected.\n"); 
+      simple = FALSE;
+   } else {
       Pmsg0(000, "Command aborted.\n");
       return;
    }
@@ -1054,9 +1085,15 @@ This may take a long time. I.e. hours! ...\n\n");
       rec.VolSessionTime = jcr->VolSessionTime;
       rec.FileIndex = ++file_index;
       rec.Stream = STREAM_FILE_DATA;
-      /* Write file_index at beginning of buffer */
+
+      /* Write file_index at beginning of buffer and add file_index to each
+       *  uint64_t item to make it unique.
+       */
       lp = (uint64_t *)rec.data;
-      *lp = (uint64_t)file_index;
+      *lp++ = (uint64_t)file_index;
+      for (uint32_t i=0; i < (REC_SIZE-sizeof(uint64_t))/sizeof(uint64_t); i++) {
+        *lp++ = *lp + rec.FileIndex;
+      }
 
       Dmsg4(250, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
         rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream, rec.FileIndex), 
@@ -1092,12 +1129,12 @@ This may take a long time. I.e. hours! ...\n\n");
            /* The weof resets the block number */
         }
 
-        if (block->BlockNumber > 10 && stop) {      /* get out */
+        if (block->BlockNumber > 10 && stop != 0) {      /* get out */
            break;
         }
       }
       if (!ok) {
-         Pmsg0(000, "Not OK\n");
+         Pmsg0(000, _("Not OK\n"));
         break;
       }
       jcr->JobBytes += rec.data_len;   /* increment bytes this job */
@@ -1105,39 +1142,45 @@ This may take a long time. I.e. hours! ...\n\n");
         FI_to_ascii(rec.FileIndex), rec.VolSessionId, 
         stream_to_ascii(rec.Stream, rec.FileIndex), 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;
+   if (stop > 0) {
+      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");
+      Pmsg0(000, _("Error in release_device\n"));
       ok = FALSE;
    }
 
    free_block(block);
    free_memory(rec.data);
-   Pmsg0(000, "Done with fill command. Now beginning re-read of tapes...\n");
+   Pmsg0(000, _("\n\nDone filling tape. Now beginning re-read of tape ...\n"));
+
+   dump_block(last_block, _("Last block written to tape.\n"));
 
    unfillcmd();
 }
 
 /*
  * Read two tapes written by the "fill" command and ensure
- *  that the data is valid.
+ *  that the data is valid.  If stop==1 we simulate full read back
+ *  of two tapes.  If stop==-1 we simply read the last block and
+ *  verify that it is correct.
  */
 static void unfillcmd()
 {
@@ -1152,7 +1195,9 @@ static void unfillcmd()
    dev->capabilities &= ~CAP_LABEL;   /* don't label anything here */
 
    end_of_tape = 0;
-   get_cmd("Mount first of two tapes. Press enter when ready: "); 
+   if (!simple) {
+      get_cmd(_("Mount first of two tapes. Press enter when ready: ")); 
+   }
    
    free_vol_list(jcr);
    pm_strcpy(&jcr->VolumeName, "TestVolume1");
@@ -1168,10 +1213,48 @@ static void unfillcmd()
    time(&jcr->run_time);             /* start counting time for rates */
    stop = 0;
    file_index = 0;
-   read_records(jcr, dev, record_cb, my_mount_next_read_volume);
+   if (!simple) {
+      /* Read all records and then second tape */
+      read_records(jcr, dev, record_cb, my_mount_next_read_volume);
+   } else {
+      /*
+       * Simplified test, we simply fsf to file, then read the
+       * last block and make sure it is the same as the saved block.
+       */
+      if (!rewind_dev(dev)) {
+         Pmsg1(-1, _("Error rewinding: ERR=%s\n"), strerror_dev(dev));
+        goto bail_out;
+      }
+      if (last_file > 0) {
+        if (!fsf_dev(dev, last_file)) {
+            Pmsg1(-1, _("Error in FSF: ERR=%s\n"), strerror_dev(dev));
+           goto bail_out;
+        }
+      }
+      Pmsg1(-1, _("Forward space to file %u complete. Reading blocks ...\n"), 
+           last_file);
+      Pmsg1(-1, _("Now reading to block %u.\n"), last_block_num);
+      for (uint32_t i= 0; i < last_block_num; i++) {
+        if (!read_block_from_device(dev, block)) {
+            Pmsg1(-1, _("Error reading blocks: ERR=%s\n"), strerror_dev(dev));
+            Pmsg2(-1, _("Wanted block %u error at block %u\n"), last_block_num, i);
+           goto bail_out;
+        }
+        if (i > 0 && i % 1000 == 0) {
+            Pmsg1(-1, _("At block %u\n"), i);
+        }
+      }
+      dump_block(last_block, _("Last block written"));
+      dump_block(block, _("Block read back"));
+      Pmsg0(-1, _("Except for the buffer address, the contents of\n"
+                  "the above two block dumps should be the same.\n"
+                  "If not you have a problem ...\n"));
+   }
+
+bail_out:
    free_block(block);
 
-   Pmsg0(000, "Done with unfillcmd.\n");
+   Pmsg0(000, _("Done with reread of fill data.\n"));
 }
 
 
@@ -1277,6 +1360,22 @@ static int flush_block(DEV_BLOCK *block, int dump)
 {
    char ec1[50];
    lock_device(dev);
+   DEV_BLOCK *tblock;
+   uint32_t this_file, this_block_num;
+
+   if (!this_block) {
+      this_block = new_block(dev);
+   }
+   /* Copy block */
+   memcpy(this_block, block, sizeof(DEV_BLOCK));
+   if (this_block->buf_len < block->buf_len) {
+      free_memory(this_block->buf);    
+      this_block->buf = get_memory(block->buf_len);
+      this_block->buf_len = block->buf_len;
+   }
+   memcpy(this_block->buf, block->buf, this_block->buf_len);
+   this_file = dev->file;
+   this_block_num = dev->block_num;
    if (!write_block_to_dev(jcr, dev, block)) {
       Pmsg0(000, strerror_dev(dev));           
       Pmsg3(000, "Block not written: FileIndex=%u Block=%u Size=%u\n", 
@@ -1284,7 +1383,7 @@ static int flush_block(DEV_BLOCK *block, int dump)
       if (dump) {
          dump_block(block, "Block not written");
       }
-      if (!stop) {
+      if (stop == 0) {
         eot_block = block->BlockNumber;
         eot_block_len = block->block_len;
         eot_FileIndex = file_index;
@@ -1298,16 +1397,34 @@ static int flush_block(DEV_BLOCK *block, int dump)
       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;
+
+      if (simple) {
+        stop = -1;                   /* stop, but do simplified test */
+      } else {
+        /* Full test in progress */
+        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;
+        }
+        stop = 1;                                                     
       }
-      stop = 1;                                                    
       unlock_device(dev);
-      return 1;     /* write one more block to next tape then stop */
+      return 1;                      /* end of tape reached */
    }
+
+   /*
+    * Toggle between two allocated blocks for efficiency.
+    * Switch blocks so that the block just successfully written is
+    *  always in last_block. 
+    */
+   tblock = last_block;
+   last_block = this_block; 
+   this_block = tblock;
+   last_file = this_file;
+   last_block_num = this_block_num;
+
    unlock_device(dev);
    return 1;
 }
index 4e0e093da4d7defc90985249f8c69ea4d12b593a..7049b43262f9628fe0a9947d07c0ec51d98f6223 100644 (file)
@@ -401,8 +401,8 @@ eod_dev(DEVICE *dev)
       }
       while (!(dev->state & ST_EOT)) {
          Dmsg0(200, "Do fsf 1\n");
-        if (fsf_dev(dev, 1) < 0) {
-            Dmsg0(200, "fsf_dev return < 0\n");
+        if (!fsf_dev(dev, 1)) {
+            Dmsg0(200, "fsf_dev error.\n");
            return 0;
         }
       }
@@ -629,6 +629,8 @@ int offline_dev(DEVICE *dev)
 
 /* 
  * Foward space a file 
+ *   Returns: 1 on success
+ *           0 on failure
  */
 int
 fsf_dev(DEVICE *dev, int num)
@@ -641,16 +643,16 @@ fsf_dev(DEVICE *dev, int num)
       dev->dev_errno = EBADF;
       Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
-      return -1;
+      return 0;
    }
 
    if (!(dev->state & ST_TAPE)) {
-      return 0;
+      return 1;
    }
    if (dev->state & ST_EOT) {
       dev->dev_errno = 0;
       Mmsg1(&dev->errmsg, _("Device %s at End of Tape.\n"), dev->dev_name);
-      return -1;
+      return 0;
    }
    if (dev->state & ST_EOF)
       Dmsg0(200, "ST_EOF set on entry to FSF\n");
@@ -736,7 +738,7 @@ fsf_dev(DEVICE *dev, int num)
    if (dev->state & ST_EOT)
       Dmsg0(200, "ST_EOT set on exit FSF\n");
    Dmsg1(200, "Return from FSF file=%d\n", dev->file);
-   return stat;
+   return stat == 0 ? 1 : 0;
 }
 
 /* 
@@ -989,10 +991,9 @@ static void do_close(DEVICE *dev)
    /* Clean up device packet so it can be reused */
    dev->fd = -1;
    dev->state &= ~(ST_OPENED|ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
-   dev->block_num = 0;
-   dev->file = 0;
+   dev->file = dev->block_num = 0;
    dev->file_addr = 0;
-   dev->LastBlockNumWritten = 0;
+   dev->EndFile = dev->EndBlock = 0;
    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
    dev->use_count--;
index 39eb20b997f55e8b86b4e05e7d15f391d7f9224d..70c750ba205c09d1ad76f24c70b428b4e2a1c4b3 100644 (file)
@@ -150,7 +150,8 @@ typedef struct s_device {
    uint32_t block_num;                /* current block number base 0 */
    uint32_t file;                     /* current file number base 0 */
    uint64_t file_addr;                /* Current file read/write address */
-   uint32_t LastBlockNumWritten;      /* last block written */
+   uint32_t EndBlock;                 /* last block written */
+   uint32_t EndFile;                  /* last file written */
    uint32_t min_block_size;           /* min block size */
    uint32_t max_block_size;           /* max block size */
    uint32_t max_volume_jobs;          /* max jobs to put on one volume */
index 671748d4af4ad3a406109e94a23d2f5cbb27ed25..4dd374b1642c55cddb90098e5256cb48ebb9a3f6 100644 (file)
@@ -93,8 +93,9 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
          Dmsg1(100, "create JobMedia for Job %s\n", mjcr->Job);
         if (dev->state & ST_TAPE) {
-           mjcr->EndBlock = dev->block_num;
-           mjcr->EndFile = dev->file;
+           mjcr->EndBlock = dev->EndBlock;
+           mjcr->EndFile  = dev->EndFile;
+            Dmsg2(000, "Fixup EndFile=%u EndBlock=%u\n", mjcr->EndFile, mjcr->EndBlock);
         } else {
            mjcr->EndBlock = (uint32_t)dev->file_addr;
            mjcr->EndFile = (uint32_t)(dev->file_addr >> 32);
index 4a2ab8bb6fb337a8979c96daad9dd8e7da427611..92a23dff258755ddfb9cef6f809d247508e17c95 100644 (file)
@@ -355,6 +355,9 @@ static int create_volume_label(DEVICE *dev, char *VolName)
       dev->VolHdr.label_time = dt.julian_day_fraction;
    }
 
+   if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
+      dev->VolHdr.HostName[0] = 0;
+   }
    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, DATE);
    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
@@ -515,8 +518,8 @@ int write_session_label(JCR *jcr, DEV_BLOCK *block, int label)
         break;
       case EOS_LABEL:
         if (dev->state & ST_TAPE) {
-           jcr->EndBlock = dev->block_num;
-           jcr->EndFile  = dev->file;
+           jcr->EndBlock = dev->EndBlock;
+           jcr->EndFile  = dev->EndFile;
         } else {
            jcr->EndBlock = (uint32_t)dev->file_addr;
            jcr->EndFile = (uint32_t)(dev->file_addr >> 32);
index 31d3add420a1b5f869c63c4c37e7eb22a36c3073..88de341080095c5692525e2ca3ec6f3f78303478 100644 (file)
@@ -66,9 +66,8 @@ mount_next_vol:
       /* 
        * First erase all memory of the current volume  
        */
-      dev->block_num = 0;
-      dev->file = 0;
-      dev->LastBlockNumWritten = 0;
+      dev->block_num = dev->file = 0;
+      dev->EndBlock = dev->EndFile = 0;
       memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
       memset(&jcr->VolCatInfo, 0, sizeof(jcr->VolCatInfo));
       memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
index c9a4bd5c2537e0b016934e5696007fabcb90cb80..ea7c602686352cfc49cf825200ef149e167c1440 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #define VERSION "1.28"
 #define VSTRING "1"
-#define DATE    "12 December 2002"
-#define LSMDATE "12Dec02"
+#define DATE    "16 December 2002"
+#define LSMDATE "16Dec02"
 
 /* Debug flags */
 #define DEBUG 1