]> git.sur5r.net Git - bacula/bacula/commitdiff
Minor changes
authorKern Sibbald <kern@sibbald.com>
Wed, 30 Oct 2002 10:29:51 +0000 (10:29 +0000)
committerKern Sibbald <kern@sibbald.com>
Wed, 30 Oct 2002 10:29:51 +0000 (10:29 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@177 91ce42f0-d328-0410-95d8-f526ca767f89

14 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_restore.c
bacula/src/dird/ua_run.c
bacula/src/jcr.h
bacula/src/stored/.cvsignore
bacula/src/stored/Makefile.in
bacula/src/stored/bcopy.c [new file with mode: 0644]
bacula/src/stored/block.c
bacula/src/stored/dev.c
bacula/src/stored/read_record.c
bacula/src/version.h

index ad94b20945746ca6e41ac2a421a0471268d0289d..bd14c95fb6f93fcb568633225315b76a3acccaad 100644 (file)
@@ -1,45 +1,33 @@
                  Kern's ToDo List
-                 29 October 2002
+                 30 October 2002
 
 To do:    
 - Document that two Verifys at same time on same client do not work.
 - Document how to recycle a tape in 7 days even if the backup takes a long time.
-
-- Figure out why my Catalog size keeps growing (Filename and Path
-  tables keep growing) -- fix it.
-
-- Add Doc on saving MySQL databases, where to find code for shutting 
+- Document to have patience when SD first starts.
+- Document running a test version.
+- Document buffer size considerations with Sparse files --
+- Document saving MySQL databases, where to find code for shutting 
   down and saving other databases.
 
 For 1.27 release:
 - Continue improving the restore process (handling
   of tapes, efficiency improvements e.g. use FSF to
   position the tape, ...)
-- Allow restore with options (e.g. overwrite, overwrite
-  if newer, no overwrite, permit changing ownership, ...).
-- Test recovery of a damaged tape.
 - Work more on how to to a Bacula restore beginning with
   just a Bacula tape and a boot floppy (bare metal recovery).
-- Possibly add a File System Module permitting an external
-  program do the file reading and writing during save and
-  restore (i.e. with this you could backup/restore
-  ANYTHING to and from a Bacula Volume, including horrible
-  stuff like Windows ACLs).
 
+- Finish implementation of restore "replace" options, and document.
 - Write bcopy program.
-- Preprocessing command per file.
-- Postprocessing command per file (when restoring).
-- File system type from File daemon
+- Recovery of a bad tape (bcopy)
+
+- Program files (i.e. execute a program to read/write files).
+  Pass read date of last backup, size of file last time.
+
+- Put system type returned by FD into catalog.
 - Decide what to do with JobTDate in catalog (make real btime_t?)
-- File daemon should pass Director the operating system info
-  to be stored in the Client Record (or verified that it has
-  not changed).
 - Add VOLUME_CAT_INFO to the EOS tape record (as
   well as to the EOD record).
-- Send Volumes needed during restore to Console (just after
-  create_volume_list) -- also in restore command?
-- Document buffer size considerations with Sparse files --
-- Move block size code from block.c to init_dev().
 - Add code to fast seek to proper place on tape/file
   when doing Restore. If it doesn't work, try linear
   search as before.
@@ -48,21 +36,14 @@ For 1.27 release:
   long and a job is waiting on the drive.
 - What to do with btime and JobTDate?
 - Add FileSet MD5 to bscan.
-- Finish implementation of restore "replace" options, and document.
 - Strip trailing slashes from Include directory names in the FD.
 - Use read_record.c in SD code.
-- Allow changing ownership/group of files on restore.
-- Restore options (overwrite, ...)
-- Program files (i.e. execute a program to read/write files).
-  Pass read date of last backup, size of file last time.
 - Try bare metal Windows restore
-- Recovery of a bad tape (bcopy)
-- EOM records?????????????????
+- Add EOM records ???????
 - Why don't we get an error message from Win32 FD when bootstrap 
   file cannot be created for restore command?
-- Put MaximumVolumeSize in Director.
-- Document to have patience when SD first starts.
-- Document running a test version.
+- Put MaximumVolumeSize in Director (MaximumVolumeJobs, MaximumVolumeFiles,
+   MaximumFileSize).
 - When Marking a file in Restore that is a hard link, also
   mark the link so that the data will be reloaded.
 - Restore program that errors in SD due to no tape reports
@@ -72,7 +53,16 @@ For 1.27 release:
   in block, done when count is reached, and possibly other
   optimizations. I.e. add a state word.
 
+Test:
+- that restore prints volumes.
+- that restore options work in FD.
+- that mod of restore options works.
+- that Bacula won't write on tape where tape/catalog files differ.
+- that console command line options work
+
 After 1.27
+- Make sure catalog doesn't keep growing.
+- Permit changing ownership during restore.
 - After unmount, if restore job started, ask to mount.
 - Fix db_get_fileset in cats/sql_get.c for multiple records.
 - Fix start/end blocks for File devices
@@ -561,3 +551,8 @@ Done: (see kernsdone for more)
 - Document all daemon tools MUST have a config file.
 - Why does btape error when pointed to a file?
 - Disallow compile if long long not 64 bits.
+- Send Volumes needed during restore to Console (just after
+  create_volume_list) -- also in restore command?
+- File system type from File daemon
+- Move block size code from block.c to init_dev().
+
index d737a7e08cd56bbe854e2b92d14d3cc56287b18a..a5a4d12f1eec02905d5ce4e8ab046f05c1711beb 100644 (file)
@@ -63,6 +63,7 @@ static void store_backup(LEX *lc, struct res_items *item, int index, int pass);
 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);
 
 
 /* We build the current resource here as we are
@@ -173,6 +174,7 @@ static struct res_items job_items[] = {
    {"client",   store_res,     ITEM(res_job.client),   R_CLIENT, 0, 0},
    {"fileset",  store_res,     ITEM(res_job.fileset),  R_FILESET, 0, 0},
    {"where",    store_dir,     ITEM(res_job.RestoreWhere), 0, 0, 0},
+   {"replace",  store_replace, ITEM(res_job.replace), 'a', ITEM_DEFAULT, 0},
    {"bootstrap",store_dir,     ITEM(res_job.RestoreBootstrap), 0, 0, 0},
    {"maxruntime", store_time,  ITEM(res_job.MaxRunTime), 0, 0, 0},
    {"maxstartdelay", store_time,ITEM(res_job.MaxStartDelay), 0, 0, 0},
@@ -330,7 +332,7 @@ static struct s_kw RestoreFields[] = {
 };
 
 /* Options permitted in Restore replace= */
-static struct s_kw ReplaceOptions[] = {
+struct s_kw ReplaceOptions[] = {
    {"always",         'a'},           /* always */
    {"ifnewer",        'w'},
    {"never",          'n'},
@@ -990,7 +992,24 @@ static void store_level(LEX *lc, struct res_items *item, int index, int pass)
    set_bit(index, res_all.hdr.item_present);
 }
 
-
+static void store_replace(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token, i;
+   token = lex_get_token(lc, T_NAME);
+   /* Scan Replacement options */
+   for (i=0; ReplaceOptions[i].name; i++) {
+      if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
+         ((JOB *)(item->value))->replace = ReplaceOptions[i].token;
+        i = 0;
+        break;
+      }
+   }
+   if (i != 0) {
+      scan_err1(lc, "Expected a Restore replacement option, got: %s", lc->str);
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
 
 /* 
  * Store backup/verify info for Job record 
@@ -1170,7 +1189,7 @@ static void store_restore(LEX *lc, struct res_items *item, int index, int pass)
                  /* Fix to scan Replacement options */
                  for (i=0; ReplaceOptions[i].name; i++) {
                     if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
-                        ((JOB *)(item->value))->RestoreOptions = ReplaceOptions[i].token;
+                        ((JOB *)(item->value))->replace = ReplaceOptions[i].token;
                        i = 0;
                        break;
                     }
index 22c38264a6c97531378b3e713fcf1ddf0f66a018..34e6944638ec3ef1655fe2e15713e856de9dc197 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_LAST                       R_COUNTER
 
 /*
  * 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 +78,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;
-   btime_t FDConnectTimeout;          /* timeout for connect in seconds */
-   btime_t SDConnectTimeout;          /* timeout in seconds */
+   int  MaxConcurrentJobs;
+   btime_t FDConnectTimeout;         /* timeout for connect in seconds */
+   btime_t SDConnectTimeout;         /* timeout in seconds */
 };
 typedef struct s_res_dir DIRRES;
 
@@ -102,12 +102,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? */
-   btime_t FileRetention;             /* file retention period in seconds */
-   btime_t JobRetention;              /* job retention period in seconds */
+   int  FDport;                      /* Where File daemon listens */
+   int  AutoPrune;                   /* Do automatic pruning? */
+   btime_t FileRetention;            /* file retention period in seconds */
+   btime_t JobRetention;             /* job retention period in seconds */
    char *address;
    char *password;
    struct s_res_cat    *catalog;       /* Catalog resource */
@@ -119,15 +119,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 +136,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 +151,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   RestoreOptions;              /* How (overwrite, ..) */
-   btime_t MaxRunTime;                /* max run time in seconds */
-   btime_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, ..) */
+   btime_t MaxRunTime;               /* max run time in seconds */
+   btime_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 +183,7 @@ typedef struct s_res_job JOB;
  *
  */
 struct s_res_fs {
-   RES   hdr;
+   RES  hdr;
 
    char **include_array;
    int num_includes;
@@ -191,9 +191,9 @@ 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;
  
@@ -203,7 +203,7 @@ typedef struct s_res_fs FILESET;
  *
  */
 struct s_res_sch {
-   RES   hdr;
+   RES  hdr;
 
    struct s_run *run;
 };
@@ -214,7 +214,7 @@ typedef struct s_res_sch SCHED;
  *
  */
 struct s_res_group {
-   RES   hdr;
+   RES  hdr;
 };
 typedef struct s_res_group GROUP;
 
@@ -222,12 +222,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,19 +236,19 @@ 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 */
-   int   max_volumes;                 /* max number of volumes */
-   btime_t VolRetention;              /* volume retention period in seconds */
-   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 */
+   int  max_volumes;                 /* max number of volumes */
+   btime_t VolRetention;             /* volume retention period in seconds */
+   int  AutoPrune;                   /* default for pool auto prune */
+   int  Recycle;                     /* default for media recycle yes/no */
 };
 typedef struct s_res_pool POOL;
 
@@ -257,16 +257,16 @@ 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;
    RES hdr;
 };
@@ -276,17 +276,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 c276d964570c7607e3d219c5be682cd44c96720c..9c686b7656671095c5579aeebaf9750416c51c1f 100644 (file)
@@ -230,8 +230,8 @@ int do_restore(JCR *jcr)
    /* Send restore command */
    char replace, *where;
 
-   if (jcr->job->RestoreOptions != 0) {
-      replace = jcr->job->RestoreOptions;
+   if (jcr->job->replace != 0) {
+      replace = jcr->job->replace;
    } else {
       replace = 'a';                  /* always replace */
    }
index 13ac6a99b9e4a6880f1297e315bddd0fc62a1d8f..c0a957821f59e0d0cafa2f0935aa8c0973d03ac4 100644 (file)
@@ -683,6 +683,7 @@ static int write_bsr_file(UAContext *ua, RBSR *bsr)
    FILE *fd;
    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
    int stat;
+   RBSR *nbsr;
 
    Mmsg(&fname, "%s/restore.bsr", working_directory);
    fd = fopen(fname, "w+");
@@ -695,7 +696,14 @@ static int write_bsr_file(UAContext *ua, RBSR *bsr)
    write_bsr(ua, bsr, fd);
    stat = !ferror(fd);
    fclose(fd);
-// bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
+   bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
+   bsendmsg(ua, _("\nThe restore job will require the following Volumes:\n"));
+   for (nbsr=bsr; nbsr; nbsr=nbsr->next) {
+      if (nbsr->VolumeName) {
+         bsendmsg(ua, "   %s\n", nbsr->VolumeName);
+      }
+   }
+   bsendmsg(ua, "\n");
    free_pool_memory(fname);
    return stat;
 }
index 98e998e73cc031a2c4c41e7d6be4555868ae1052..be33e03479e5c028440d568b500c496f77583837 100644 (file)
@@ -36,6 +36,7 @@ extern void run_job(JCR *jcr);
 
 /* Imported variables */
 extern struct s_jl joblevels[];
+extern struct s_kw ReplaceOptions[];
 
 /*
  * For Backup and Verify Jobs
@@ -49,8 +50,8 @@ int runcmd(UAContext *ua, char *cmd)
 {
    JCR *jcr;
    char *job_name, *level_name, *jid, *store_name;
-   char *where, *fileset_name, *client_name, *bootstrap;
-   int i, j, found;
+   char *where, *fileset_name, *client_name, *bootstrap, *replace;
+   int i, j, found, opt;
    JOB *job = NULL;
    STORE *store = NULL;
    CLIENT *client = NULL;
@@ -64,6 +65,7 @@ int runcmd(UAContext *ua, char *cmd)
       N_("storage"),
       N_("where"),
       N_("bootstrap"),
+      N_("replace"),
       NULL};
 
    if (!open_db(ua)) {
@@ -78,6 +80,7 @@ int runcmd(UAContext *ua, char *cmd)
    client_name = NULL;
    fileset_name = NULL;
    bootstrap = NULL;
+   replace = NULL;
 
    for (i=1; i<ua->argc; i++) {
       found = False;
@@ -154,6 +157,14 @@ int runcmd(UAContext *ua, char *cmd)
                  bootstrap = ua->argv[i];
                  found = True;
                  break;
+              case 8: /* replace */
+                 if (replace) {
+                     bsendmsg(ua, _("Replace specified twice.\n"));
+                    return 1;
+                 }
+                 replace = ua->argv[i];
+                 found = True;
+                 break;
               default:
                  break;
            }
@@ -256,8 +267,28 @@ int runcmd(UAContext *ua, char *cmd)
       jcr->RestoreBootstrap = bstrdup(bootstrap);
    }
 
-
-
+   if (replace) {
+      jcr->replace = 0;
+      for (i=0; ReplaceOptions[i].name; i++) {
+        if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
+           jcr->replace = ReplaceOptions[i].token;
+        }
+      }
+      if (!jcr->replace) {
+         bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
+        return 0;
+      }
+   } else if (job->replace) {
+      jcr->replace = job->replace;
+   } else {
+      jcr->replace = 'a';
+   }
+   replace = ReplaceOptions[0].name;
+   for (i=0; ReplaceOptions[i].name; i++) {
+      if (ReplaceOptions[i].token == jcr->replace) {
+        replace = ReplaceOptions[i].name;
+      }
+   }
 
 try_again:
    Dmsg1(20, "JobType=%c\n", jcr->JobType);
@@ -326,6 +357,7 @@ Storage:  %s\n"),
 JobName:    %s\n\
 Bootstrap:  %s\n\
 Where:      %s\n\
+Replace:    %s\n\
 FileSet:    %s\n\
 Client:     %s\n\
 Storage:    %s\n\
@@ -333,6 +365,7 @@ JobId:      %s\n"),
                 job->hdr.name,
                 NPRT(jcr->RestoreBootstrap),
                 jcr->RestoreWhere?jcr->RestoreWhere:NPRT(job->RestoreWhere),
+                replace,
                 jcr->fileset->hdr.name,
                 jcr->client->hdr.name,
                 jcr->store->hdr.name, 
@@ -367,7 +400,8 @@ JobId:      %s\n"),
       if (jcr->JobType == JT_RESTORE) {
          add_prompt(ua, _("Bootstrap"));     /* 5 */
          add_prompt(ua, _("Where"));         /* 6 */
-         add_prompt(ua, _("JobId"));         /* 7 */
+         add_prompt(ua, _("Replace"));       /* 7 */
+         add_prompt(ua, _("JobId"));         /* 8 */
       }
       switch (do_prompt(ua, _("Select parameter to modify"), NULL)) {
       case 0:
@@ -494,6 +528,17 @@ JobId:      %s\n"),
         jcr->RestoreWhere = bstrdup(ua->cmd);
         goto try_again;
       case 7:
+        /* Replace */
+         start_prompt(ua, _("Replace:\n"));
+        for (i=0; ReplaceOptions[i].name; i++) {
+           add_prompt(ua, ReplaceOptions[i].name);
+        }
+         opt = do_prompt(ua, _("Select replace option"), NULL);
+        if (opt <=  0) {
+           jcr->replace = ReplaceOptions[opt].token;
+        }
+        goto try_again;
+      case 8:
         /* JobId */
         jid = NULL;                  /* force reprompt */
         jcr->RestoreJobId = 0;
index e7bfc436bca2fa5cfaad5d6346b0deb2b7b3cb3f..368b39319ad7c1a9dbe694934d5881c311b2a37a 100644 (file)
@@ -141,6 +141,7 @@ struct s_jcr {
    uint32_t RestoreJobId;             /* Id specified by UA */
    char *RestoreWhere;                /* Where to restore the files */
    POOLMEM *client_uname;             /* client uname */ 
+   int replace;                       /* Replace option */
 #endif /* DIRECTOR_DAEMON */
 
 #ifdef FILE_DAEMON
index 6802ea651b4cd9b524dc65275424d35bb2d2edda..7446154068eef8376cc14a94c32e817861b844de 100644 (file)
@@ -6,6 +6,7 @@ bextract
 bls
 bscan
 btape
+bcopy
 btraceback
 btraceback.gdb
 file1Job1.bsr
index 5216ca33c72532da82e55fa4afdcab16f22adac4..500f6a3569aaf8fc9b626cb6e922fdd666c9232d 100644 (file)
@@ -52,14 +52,10 @@ 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 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 
-
-
+# bcopy
+COPYOBJS = bcopy.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 stored_conf.o
 
 
 
@@ -77,16 +73,13 @@ FDLIBS=@FDLIBS@
 .c.o:
        $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
 #-------------------------------------------------------------------------
-all: Makefile bacula-sd bls bextract bscan btape 
+all: Makefile bacula-sd bls bextract bscan btape
        @echo "===== Make of stored is good ===="
        @echo " "
 
 bacula-sd: $(SVROBJS) ../lib/libbac.a
        $(CXX) $(LDFLAGS) -L../lib -o $@ $(SVROBJS) $(FDLIBS) -lbac -lm $(LIBS) $(DLIB)
 
-#bpool:  $(POOLOBJS) ../lib/libbac.a ../cats/libsql.a
-#       $(CXX) $(LDFLAGS) -L../lib -L../cats  -o $@ $(POOLOBJS) -lsql $(LIBS) $(DLIB) -lbac -lm
-
 btape: $(TAPEOBJS) ../lib/libbac.a ../cats/libsql.a
        $(CXX) $(TTOOL_LDFLSGS) $(LDFLAGS) -L../lib -L../cats  -o $@ $(TAPEOBJS) -lsql $(LIBS) $(DLIB) -lbac -lm
 
@@ -96,10 +89,11 @@ bls:        ../findlib/libfind.a $(BLSOBJS) ../lib/libbac.a
 bextract: ../findlib/libfind.a $(BEXTOBJS) ../lib/libbac.a
        $(CXX) $(TTOOL_LDFLAGS) $(LDFLAGS) -L../lib -L../findlib -o $@ $(BEXTOBJS) $(LIBS) $(DLIB) $(FDLIBS) -lfind -lbac -lm
 
-bscan: ../findlib/libfind.a $(SCNOBJS) ../cats/libsql.a
+bscan: ../findlib/libfind.a $(SCNOBJS) ../cats/libsql.a
        $(CXX) $(TTOOL_LDFLAGS) $(LDFLAGS) -L../lib -L../cats -L../findlib -o $@ $(SCNOBJS) -lsql $(LIBS) $(DB_LIBS) $(FDLIBS) -lfind -lbac -lm
 
-
+bcopy: $(COPYOBJS) ../findlib/libfind.a ../lib/libbac.a
+       $(CXX) $(TTOOL_LDFLAGS) $(LDFLAGS) -L../lib -L../findlib -o $@ $(COPYOBJS)  $(LIBS) $(DB_LIBS) $(FDLIBS) -lfind -lbac -lm
 
 
 Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
@@ -110,7 +104,8 @@ install: all
        $(INSTALL_PROGRAM) bacula-sd $(DESTDIR)$(sbindir)/bacula-sd
        $(INSTALL_PROGRAM) bls $(DESTDIR)$(sbindir)/bls
        $(INSTALL_PROGRAM) bextract $(DESTDIR)$(sbindir)/bextract
-#      $(INSTALL_PROGRAM) bpool $(DESTDIR)$(sbindir)/bpool
+       $(INSTALL_PROGRAM) bcopy $(DESTDIR)$(sbindir)/bcopy
+       $(INSTALL_PROGRAM) bscan $(DESTDIR)$(sbindir)/bscan
        $(INSTALL_PROGRAM) btape $(DESTDIR)$(sbindir)/btape
        @srcconf=bacula-sd.conf; \
        if  test -f ${DESTDIR}${sysconfdir}/$$srcconf; then \
@@ -126,13 +121,15 @@ uninstall:
        (cd $(DESTDIR)$(sbindir); $(RMF) bacula-sd)
        (cd $(DESTDIR)$(sbindir); $(RMF) bls)
        (cd $(DESTDIR)$(sbindir); $(RMF) bextract)
-#      (cd $(DESTDIR)$(sbindir); $(RMF) bpool)
+       (cd $(DESTDIR)$(sbindir); $(RMF) bcopy)
+       (cd $(DESTDIR)$(sbindir); $(RMF) bscan)
+       (cd $(DESTDIR)$(sbindir); $(RMF) btape)
        (cd $(DESTDIR)$(sysconfdir); $(RMF) bacula-sd.conf)
 
 
 clean:
        @$(RMF) bacula-sd stored bls bextract bpool btape shmfree core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
-       @$(RMF) bscan
+       @$(RMF) bscan bcopy
 
 realclean: clean
        @$(RMF) tags bacula-sd.conf
diff --git a/bacula/src/stored/bcopy.c b/bacula/src/stored/bcopy.c
new file mode 100644 (file)
index 0000000..e8265de
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ *
+ *  Program to copy a Bacula from one volume to another.
+ *
+ *   Kern E. Sibbald, October 2002
+ *
+ *
+ *   Version $Id$
+ */
+/*
+   Copyright (C) 2001, 2002 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
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public
+   License along with this program; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+/* Forward referenced functions */
+static void do_scan(void);
+static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
+
+
+/* Global variables */
+static DEVICE *dev = NULL;
+static B_DB *db;
+static JCR *bjcr;                    /* jcr for bscan */
+static BSR *bsr = NULL;
+static char *wd = "/tmp";
+static int verbose = 0;
+
+#define CONFIG_FILE "bacula-sd.conf"
+char *configfile;
+
+
+static void usage()
+{
+   fprintf(stderr, _(
+"\nVersion: " VERSION " (" DATE ")\n\n"
+"Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
+"       -b bootstrap      specify a bootstrap file\n"
+"       -c <file>         specify configuration file\n"
+"       -dnn              set debug level to nn\n"
+"       -v                verbose\n"
+"       -w dir            specify working directory (default /tmp)\n"
+"       -?                print this message\n\n"));
+   exit(1);
+}
+
+int main (int argc, char *argv[])
+{
+   int ch;
+
+   my_name_is(argc, argv, "bscan");
+   init_msg(NULL, NULL);
+
+   fprintf(stderr, "\n\nPlease don't use this program.\n\
+It is currently under development and does not work.\n\n");
+
+   while ((ch = getopt(argc, argv, "b:c:d:mn:p:rsu:vw:?")) != -1) {
+      switch (ch) {
+         case 'b':
+           bsr = parse_bsr(NULL, optarg);
+           break;
+
+         case 'c':                    /* specify config file */
+           if (configfile != NULL) {
+              free(configfile);
+           }
+           configfile = bstrdup(optarg);
+           break;
+
+         case 'd':                    /* debug level */
+           debug_level = atoi(optarg);
+           if (debug_level <= 0)
+              debug_level = 1; 
+           break;
+
+         case 'v':
+           verbose++;
+           break;
+
+         case 'w':
+           wd = optarg;
+           break;
+
+         case '?':
+        default:
+           usage();
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+   if (argc != 2) {
+      Pmsg0(0, _("Wrong number of arguments: \n"));
+      usage();
+   }
+
+   working_directory = wd;
+
+   if (configfile == NULL) {
+      configfile = bstrdup(CONFIG_FILE);
+   }
+
+   parse_config(configfile);
+
+   bjcr = setup_jcr("bcopy", argv[0], bsr);
+   dev = setup_to_access_device(bjcr, 0);   /* read device */
+   if (!dev) { 
+      exit(1);
+   }
+
+   do_copy();
+
+   free_jcr(bjcr);
+   return 0;
+}
+  
+
+static void do_copy()            
+{
+   detach_jcr_from_device(dev, bjcr);
+
+   read_records(bjcr, dev, record_cb, mount_next_read_volume);
+   release_device(bjcr, dev);
+
+   term_dev(dev);
+}
+
+static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
+{
+   JCR *mjcr;
+   char ec1[30];
+
+   if (list_records) {
+      Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
+           rec->VolSessionId, rec->VolSessionTime, rec->FileIndex, 
+           rec->Stream, rec->data_len);
+   }
+   /* 
+    * Check for Start or End of Session Record 
+    *
+    */
+   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 volume cannot be copied.\n");
+           return;
+           break;
+        case VOL_LABEL:
+            Pmsg1(000, "VOL_LABEL: OK for Volume: %s\n", mr.VolumeName);
+           break;
+        case SOS_LABEL:
+           break;
+        case EOS_LABEL:
+           break;
+        case EOM_LABEL:
+           break;
+        case EOT_LABEL:              /* end of all tapes */
+           break;
+        default:
+           break;
+      }
+      return;
+   }
+
+   /*  Write record */
+
+   return;
+}
+
+/*
+ * Free the Job Control Record if no one is still using it.
+ *  Called from main free_jcr() routine in src/lib/jcr.c so
+ *  that we can do our Director specific cleanup of the jcr.
+ */
+static void dird_free_jcr(JCR *jcr)
+{
+   Dmsg0(200, "Start dird free_jcr\n");
+
+   if (jcr->file_bsock) {
+      Dmsg0(200, "Close File bsock\n");
+      bnet_close(jcr->file_bsock);
+   }
+   if (jcr->store_bsock) {
+      Dmsg0(200, "Close Store bsock\n");
+      bnet_close(jcr->store_bsock);
+   }
+   if (jcr->RestoreBootstrap) {
+      free(jcr->RestoreBootstrap);
+   }
+   Dmsg0(200, "End dird free_jcr\n");
+}
+
+
+
+/* 
+ * Create a JCR as if we are really starting the job
+ */
+static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
+{
+   JCR *jobjcr;
+   /*
+    * Transfer as much as possible to the Job JCR. Most important is
+    *  the JobId and the ClientId.
+    */
+   jobjcr = new_jcr(sizeof(JCR), dird_free_jcr);
+   jobjcr->JobType = jr->Type;
+   jobjcr->JobLevel = jr->Level;
+   jobjcr->JobStatus = jr->JobStatus;
+   strcpy(jobjcr->Job, jr->Job);
+   jobjcr->JobId = JobId;      /* this is JobId on tape */
+   jobjcr->sched_time = jr->SchedTime;
+   jobjcr->start_time = jr->StartTime;
+   jobjcr->VolSessionId = rec->VolSessionId;
+   jobjcr->VolSessionTime = rec->VolSessionTime;
+   jobjcr->ClientId = jr->ClientId;
+   attach_jcr_to_device(dev, jobjcr);
+   return jobjcr;
+}
+
+/* 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_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { 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)
+{
+   /*  
+    * We are at the end of reading a tape. Now, we simulate handling
+    *  the end of writing a tape by wiffling through the attached
+    *  jcrs creating jobmedia records.
+    */
+   Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
+   for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+      if (verbose) {
+         Pmsg1(000, "create JobMedia for Job %s\n", mjcr->Job);
+      }
+      if (dev->state & ST_TAPE) {
+        mjcr->EndBlock = dev->block_num;
+        mjcr->EndFile = dev->file;
+      } else {
+        mjcr->EndBlock = (uint32_t)dev->file_addr;
+        mjcr->StartBlock = (uint32_t)(dev->file_addr >> 32);
+      }
+      if (!create_jobmedia_record(db, mjcr)) {
+         Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
+           dev->VolCatInfo.VolCatName, mjcr->Job);
+      }
+   }
+
+   fprintf(stderr, "Mount Volume %s on device %s and press return when ready: ",
+      jcr->VolumeName, dev_name(dev));
+   getchar();  
+   return 1;
+}
index 6d1df90b4dcf141dfdda4247a7525a0e6b3d9251..8e1b01caaa1df7b52f89a38ef421d60b76cf2a8f 100644 (file)
@@ -112,15 +112,6 @@ DEV_BLOCK *new_block(DEVICE *dev)
    } else {
       block->buf_len = dev->max_block_size;
    }
-   /* ****FIXME***** move this up to init_dev() */
-   if (block->buf_len % TAPE_BSIZE != 0) {
-      uint32_t old_len = block->buf_len;
-      block->buf_len = ((old_len + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
-      Mmsg3(&dev->errmsg, _("Block size %u forced to %u to be multiple of %d\n"), 
-        old_len, block->buf_len, TAPE_BSIZE);
-      Emsg0(M_WARNING, 0, dev->errmsg);
-      dev->max_block_size = block->buf_len;  /* force block size */
-   }
    block->block_len = block->buf_len;  /* default block size */
    block->buf = get_memory(block->buf_len); 
    if (block->buf == NULL) {
@@ -327,6 +318,7 @@ int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block)
         if (wlen < dev->min_block_size) {
            wlen =  ((dev->min_block_size + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
         }
+        /* check for fixed block size */
         if (dev->min_block_size == dev->max_block_size) {
            wlen = block->buf_len;    /* fixed block size already rounded */
         }
index 6a9ab69d1e10d93c5e52b9ea4e656ca29d79db6d..f1b62ab247f22f66d73816b76fe10af432b75077 100644 (file)
@@ -125,7 +125,7 @@ init_dev(DEVICE *dev, DEVRES *device)
       if (dev) {
         dev->dev_errno = ENODEV;
       }
-      Emsg2(M_FATAL, 0, "%s is an unknown device type. Must be tape or directory. st_mode=%x\n", 
+      Emsg2(M_FATAL, 0, _("%s is an unknown device type. Must be tape or directory. st_mode=%x\n"),
         dev_name, statp.st_mode);
       return NULL;
    }
@@ -155,7 +155,16 @@ init_dev(DEVICE *dev, DEVRES *device)
    dev->max_open_wait = device->max_open_wait;
    dev->device = device;
 
-
+   if (dev->max_block_size > 1000000) {
+      Emsg3(M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"), 
+        dev->max_block_size, dev->dev_name, DEFAULT_BLOCK_SIZE);
+      dev->max_block_size = 0;
+   }
+   if (dev->max_block_size % TAPE_BSIZE != 0) {
+      Emsg2(M_WARNING, 0, _("Max block size %u not multiple of device %s block size.\n"),
+        dev->max_block_size, dev->dev_name);
+   }   
+        
    dev->errmsg = get_pool_memory(PM_EMSG);
    *dev->errmsg = 0;
 
index f747da67c20e22cfddad114a64f45d380894747b..b324bf01f859519b169d63570c0676886b2c2072 100644 (file)
@@ -56,7 +56,7 @@ int read_records(JCR *jcr,  DEVICE *dev,
       if (!read_block_from_device(dev, block)) {
          Dmsg0(20, "!read_record()\n");
         if (dev->state & ST_EOT) {
-           DEV_RECORD *record = new_record();
+           DEV_RECORD *trec = new_record();
 
             Dmsg3(100, "EOT. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
                  block->BlockNumber, rec->remainder);
@@ -69,11 +69,11 @@ int read_records(JCR *jcr,  DEVICE *dev,
                *  be properly updated because this is the last
                *  tape.
                */
-              record->FileIndex = EOT_LABEL;
-              record->File = dev->file;
-              record->Block = rec->Block; /* return block last read */
-              record_cb(jcr, dev, block, record);
-              free_record(record);
+              trec->FileIndex = EOT_LABEL;
+              trec->File = dev->file;
+              trec->Block = rec->Block; /* return block last read */
+              record_cb(jcr, dev, block, trec);
+              free_record(trec);
               break;
            }
             Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
@@ -84,11 +84,11 @@ int read_records(JCR *jcr,  DEVICE *dev,
             *  most likely reading the previous record.
             */
            read_block_from_device(dev, block);
-           read_record_from_block(block, record);
-           get_session_record(dev, record, &sessrec);
-           record->File = dev->file;
-           record_cb(jcr, dev, block, record);
-           free_record(record);
+           read_record_from_block(block, trec);
+           get_session_record(dev, trec, &sessrec);
+           trec->File = dev->file;
+           record_cb(jcr, dev, block, trec);
+           free_record(trec);
            goto next_record;
         }
         if (dev->state & ST_EOF) {
index f5d7adfa77cd281849e1b73fc2d4588eed8aa88b..b02e1cd68b1acb23f5ab50927db55b29d51db6eb 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #define VERSION "1.27"
 #define VSTRING "1"
-#define DATE    "26 October 2002"
-#define LSMDATE "26Oct02"
+#define DATE    "30 October 2002"
+#define LSMDATE "30Oct02"
 
 /* Debug flags */
 #define DEBUG 1