]> git.sur5r.net Git - bacula/bacula/commitdiff
Implement repositioning code + misc
authorKern Sibbald <kern@sibbald.com>
Sun, 31 Aug 2003 10:29:36 +0000 (10:29 +0000)
committerKern Sibbald <kern@sibbald.com>
Sun, 31 Aug 2003 10:29:36 +0000 (10:29 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@680 91ce42f0-d328-0410-95d8-f526ca767f89

25 files changed:
bacula/kernstodo
bacula/src/cats/sql_create.c
bacula/src/cats/sql_find.c
bacula/src/cats/sql_get.c
bacula/src/console.glade
bacula/src/dird/query.sql
bacula/src/dird/sql_cmds.c
bacula/src/dird/ua_restore.c
bacula/src/dird/ua_tree.c
bacula/src/jcr.h
bacula/src/lib/tree.c
bacula/src/stored/acquire.c
bacula/src/stored/bextract.c
bacula/src/stored/block.c
bacula/src/stored/bls.c
bacula/src/stored/bsr.h
bacula/src/stored/btape.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/device.c
bacula/src/stored/fd_cmds.c
bacula/src/stored/match_bsr.c
bacula/src/stored/parse_bsr.c
bacula/src/stored/protos.h
bacula/src/stored/read_record.c

index 040852203ff30a47093058fb49a88d6158a9f5c8..c6d646a1a524ee399c2db3a5535552862b1b39b2 100644 (file)
@@ -27,6 +27,14 @@ Testing to do: (painful)
 - Figure out how to use ssh or stunnel to protect Bacula communications.
 
 For 1.32:
+- Add ExhautiveRestoreSearch and use repositioning at the beginning
+  of the tape.
+- Add Machine type (Linux/Windows) to Status report for daemons.
+- Document "status" in the console.
+- Document driving console from shell script.
+- Specify list of files to restore
+- Implement ClientRunBeforeJob and ClientRunAfterJob.
+- Restore file list.
 - Write JobMedia records with max file size is reached on tape.
 - Look at the possibility of loading only the necessary 
   data into the restore tree (i.e. do it one directory at a
@@ -293,6 +301,38 @@ For 1.32:
   > woorkstations to be shut down overnight to save power.
   > 
 
+- From Terry Manderson <terry@apnic.net>
+   jobset { # new structure
+   name = "monthlyUnixBoxen"
+   type = backup
+   level = full
+   jobs = "wakame;durian;soy;wasabi;miso" #new!
+   schedule = monthly
+   storage = DLT
+   messages = Standard
+   pool = MonthlyPool
+   priority = 10
+   }
+
+   job {
+   name = "wakame"
+    fileset = "genericUnixSet"
+   client = wakame-fd
+   }
+
+   job {
+   name = "durian"
+   fileset = "genericUnixSet"
+   client = durian-fd
+   }
+
+   job {
+   name = "soy"
+   fileset = "UnixDevelBoxSet"
+   client = soy-fd
+   }
+
+
 - Autolabel should be specified by DIR instead of SD.
 - Storage daemon    
   - Add media capacity
index 9d8875e8f16692b39c7750180b8333e9f26f916f..1406ca4dfbae2874222fafa0ca7dfa836d3804df 100644 (file)
@@ -117,6 +117,7 @@ db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
    int count;
 
    db_lock(mdb);
+#ifdef not_used_in_new_code
    Mmsg(&mdb->cmd, "SELECT JobId, MediaId FROM JobMedia WHERE \
 JobId=%d AND MediaId=%d", jm->JobId, jm->MediaId);
 
@@ -132,6 +133,7 @@ JobId=%d AND MediaId=%d", jm->JobId, jm->MediaId);
       }
       sql_free_result(mdb);
    }
+#endif
 
    /* Now get count for VolIndex */
    Mmsg(&mdb->cmd, "SELECT count(*) from JobMedia");
index 7a29ac141b72c87bd3a238101e830af676d520b6..c0379235f8473ebeeda85bb2391deaada203f49a 100644 (file)
@@ -211,7 +211,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr)
       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
 "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
-"FirstWritten,LastWritten "
+"FirstWritten,LastWritten,VolStatus "
 "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus IN ('Full',"
 "'Recycle','Purged','Used','Append') "
 "ORDER BY LastWritten LIMIT 1", mr->PoolId, mr->MediaType); 
@@ -221,7 +221,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr)
       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
 "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot,"
-"FirstWritten,LastWritten "
+"FirstWritten,LastWritten,VolStatus "
 "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' "
 "ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); 
    }
@@ -272,6 +272,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, MEDIA_DBR *mr)
    mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
    bstrncpy(mr->cLastWritten, row[18]!=NULL?row[18]:"", sizeof(mr->cLastWritten));
    mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
+   bstrncpy(mr->VolStatus, row[19], sizeof(mr->VolStatus));
 
    sql_free_result(mdb);
 
index 285558286cc0eccf8eb39e85cf925e149e9aae62..7ff3a44fe6bc409b9a0995c257e3a4f60e77ea2d 100644 (file)
@@ -311,8 +311,8 @@ int db_get_job_volume_names(JCR *jcr, B_DB *mdb, uint32_t JobId, POOLMEM **Volum
 
    db_lock(mdb);
    Mmsg(&mdb->cmd, 
-"SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%u \
-AND JobMedia.MediaId=Media.MediaId", JobId);
+"SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%u "
+"AND JobMedia.MediaId=Media.MediaId GROUP BY VolumeName", JobId);
 
    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
    *VolumeNames[0] = 0;
index 08f3d57563203e7acb18af6b0fa4786d30efb875..c9509b3c366456cdfd87eedbf5e56c3aef58ead9 100644 (file)
@@ -18,6 +18,8 @@
 <widget>
   <class>GtkWindow</class>
   <name>app1</name>
+  <width>800</width>
+  <height>500</height>
   <signal>
     <name>delete_event</name>
     <handler>on_app1_delete_event</handler>
@@ -27,7 +29,6 @@
   <type>GTK_WINDOW_TOPLEVEL</type>
   <position>GTK_WIN_POS_CENTER</position>
   <modal>False</modal>
-  <default_width>800</default_width>
   <default_height>500</default_height>
   <allow_shrink>True</allow_shrink>
   <allow_grow>True</allow_grow>
index 61ecdc4c3c29c089ae8daaf7e3c4cdfb4736fded..3ef1a80cf166dc4cc796f50a4a413d58015d4295 100644 (file)
@@ -3,7 +3,7 @@ SELECT  count(*) AS Jobs, sum(JobFiles) AS Files,
  sum(JobBytes) AS Bytes, Name AS Job FROM Job GROUP BY Name;
 SELECT max(JobId) AS Jobs,sum(JobFiles) AS Files,
  sum(JobBytes) As Bytes FROM Job;
-#
+# 2
 :List where a file is saved:
 *Enter path with trailing slash:
 *Enter filename:
@@ -20,7 +20,7 @@ SELECT Job.JobId,StartTime AS JobStartTime,VolumeName,Client.Name AS ClientName
  AND JobMedia.MediaId=Media.MediaId
  AND Client.ClientId=Job.ClientId
  GROUP BY Job.JobId;
-#
+# 3
 :List where the most recent copies of a file are saved:
 *Enter path with trailing slash:
 *Enter filename:
@@ -37,7 +37,7 @@ SELECT Job.JobId,StartTime AS JobStartTime,VolumeName,Client.Name AS ClientName
  AND JobMedia.MediaId=Media.MediaId
  AND Client.ClientId=Job.ClientId
  ORDER BY Job.StartTime DESC LIMIT 5;
-#
+# 4
 :List last 20 Full Backups for a Client:
 *Enter Client name:
 Select Job.JobId,Client.Name as Client,StartTime,JobFiles,JobBytes,
@@ -48,7 +48,7 @@ JobMedia.StartFile as VolFile,VolumeName
  AND Level='F' AND JobStatus='T'
  AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId
  ORDER BY Job.StartTime DESC LIMIT 20;
-#
+# 5
 :List all backups for a Client after a specified time
 *Enter Client Name:
 *Enter time in YYYY-MM-DD HH:MM:SS format:
@@ -60,7 +60,7 @@ Select Job.JobId,Client.Name as Client,Level,StartTime,JobFiles,JobBytes,VolumeN
   AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId
   AND Job.StartTime >= '%2'
   ORDER BY Job.StartTime;
-#
+# 6
 :List all backups for a Client
 *Enter Client Name:
 Select Job.JobId,Client.Name as Client,Level,StartTime,JobFiles,JobBytes,VolumeName
@@ -70,14 +70,14 @@ Select Job.JobId,Client.Name as Client,Level,StartTime,JobFiles,JobBytes,VolumeN
   AND JobStatus='T'
   AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId
   ORDER BY Job.StartTime;
-#
+# 7
 :List Volume Attributes for a selected Volume:
 *Enter Volume name:
 SELECT Slot,MaxVolBytes,VolCapacityBytes,VolStatus,Recycle,VolRetention,
  VolUseDuration,MaxVolJobs,MaxVolFiles
  FROM Media   
  WHERE Volumename='%1';
-#
+# 8
 :List Volumes used by selected JobId:
 *Enter JobId:
 SELECT Job.JobId,VolumeName 
@@ -85,7 +85,7 @@ SELECT Job.JobId,VolumeName
  WHERE Job.JobId=%1 
  AND Job.JobId=JobMedia.JobId 
  AND JobMedia.MediaId=Media.MediaId;
-#
+# 9
 :List Volumes to Restore All Files:
 *Enter Client Name:
 !DROP TABLE temp;
@@ -115,17 +115,20 @@ INSERT INTO temp SELECT Job.JobId,JobTDate,Job.ClientId,Job.Level,
  AND JobMedia.JobId=Job.JobId 
  AND JobMedia.MediaId=Media.MediaId
  ORDER BY Job.JobTDate DESC LIMIT 1;
-# Copy into temp 2
-INSERT INTO temp2 SELECT JobId,StartTime,VolumeName,Level,StartFile, 
-   VolSessionId,VolSessionTime
- FROM temp;
+# Copy into temp 2 getting all volumes of Full save
+INSERT INTO temp2 SELECT Job.JobId,Job.StartTime,Media.VolumeName,Job.Level,
+   JobMedia.StartFile,Job.VolSessionId,Job.VolSessionTime
+ FROM temp,Job,JobMedia,Media WHERE temp.JobId=Job.JobId
+ AND Job.Level='F' AND Job.JobStatus='T'
+ AND JobMedia.JobId=Job.JobId
+ AND JobMedia.MediaId=Media.MediaId;
 # Now add subsequent incrementals
 INSERT INTO temp2 SELECT Job.JobId,Job.StartTime,Media.VolumeName,
    Job.Level,JobMedia.StartFile,Job.VolSessionId,Job.VolSessionTime
  FROM Job,temp,JobMedia,Media
  WHERE Job.JobTDate>temp.JobTDate 
  AND Job.ClientId=temp.ClientId
- AND Job.Level='I' AND JobStatus='T'
+ AND Job.Level IN ('I','D') AND JobStatus='T'
  AND JobMedia.JobId=Job.JobId 
  AND JobMedia.MediaId=Media.MediaId
  GROUP BY Job.JobId;
@@ -133,13 +136,13 @@ INSERT INTO temp2 SELECT Job.JobId,Job.StartTime,Media.VolumeName,
 SELECT * from temp2;
 !DROP TABLE temp;
 !DROP TABLE temp2;
-#
+# 10
 :List Pool Attributes for a selected Pool:
 *Enter Pool name:
 SELECT Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes
  FROM Pool
  WHERE Name='%1';
-#
+# 11
 :List where a File is saved:
 *Enter Filename (no path):
 SELECT Job.JobId as JobId, Client.Name as Client,
index 1a9ae7a25eed9e651153d42e552bacc27da9d22b..6f78624a1358142b7a1ab715087724254a60bcc1 100644 (file)
@@ -97,7 +97,7 @@ char *select_backup_del =
    "AND Job.Level='F' "
    "AND Job.JobStatus='T' "
    "AND Job.FileSetId=DelCandidates.FileSetId) "
-   "GROUP BY JobId";
+   "GROUP BY DelCandidates.JobId";
 
 /* Select Jobs from the DelCandidates table that have a
  * more recent InitCatalog -- i.e. are not the only InitCatalog
@@ -112,7 +112,7 @@ char *select_verify_del =
    "AND Job.Level='V' "
    "AND Job.JobStatus='T' "
    "AND Job.FileSetId=DelCandidates.FileSetId "
-   "GROUP BY JobId";
+   "GROUP BY DelCandidates.JobId";
 
 
 /* Select Jobs from the DelCandidates table.
@@ -124,7 +124,7 @@ char *select_restore_del =
    "WHERE Job.JobTDate>%s "
    "AND Job.ClientId=%u "   
    "AND Job.Type='R' "
-   "GROUP BY JobId";
+   "GROUP BY DelCandidates.JobId";
 
 
 
@@ -135,7 +135,7 @@ char *uar_list_jobs =
    "SELECT JobId,Client.Name as Client,StartTime,Level as "
    "JobLevel,JobFiles,JobBytes "
    "FROM Client,Job WHERE Client.ClientId=Job.ClientId AND JobStatus='T' "
-   "AND Type='B' ORDER BY StartTime LIMIT 20";
+   "AND Type='B' ORDER BY StartTime DESC LIMIT 20";
 
 #ifdef HAVE_MYSQL
 /*  MYSQL IS NOT STANDARD SQL !!!!! */
index fa13461724bf35f279be4bf7c987031c0f7d0b7d..3ffffe1ef2b8e5dddf7137330b112543735040f9 100644 (file)
@@ -53,6 +53,7 @@ struct JOBIDS {
    utime_t JobTDate;
    uint32_t TotalFiles;
    char ClientName[MAX_NAME_LENGTH];
+   char last_jobid[10];
    char JobIds[200];                 /* User entered string of JobIds */
    STORE  *store;
 };
@@ -176,7 +177,7 @@ int restorecmd(UAContext *ua, char *cmd)
          bsendmsg(ua, "%s", db_strerror(ua->db));
       }
    }
-   bsendmsg(ua, "%d item%s inserted into the tree and marked for extraction.\n", 
+   bsendmsg(ua, "%d Job%s inserted into the tree and marked for extraction.\n", 
       items, items==1?"":"s");
    free_pool_memory(query);
 
@@ -423,6 +424,9 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji)
       if (stat == 0) {
         break;
       }
+      if (jr.JobId == JobId) {
+        continue;                    /* duplicate of last JobId */
+      }
       jr.JobId = JobId;
       if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
          bsendmsg(ua, _("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
@@ -519,6 +523,7 @@ static int select_backups_before_date(UAContext *ua, JOBIDS *ji, char *date)
 
    /* Get the JobIds from that list */
    ji->JobIds[0] = 0;
+   ji->last_jobid[0] = 0;
    if (!db_sql_query(ua->db, uar_sel_jobid_temp, jobid_handler, (void *)ji)) {
       bsendmsg(ua, "%s\n", db_strerror(ua->db));
    }
@@ -569,6 +574,10 @@ static int jobid_handler(void *ctx, int num_fields, char **row)
 {
    JOBIDS *ji = (JOBIDS *)ctx;
 
+   if (strcmp(ji->last_jobid, row[0]) == 0) {          
+      return 0;                      /* duplicate id */
+   }
+   bstrncpy(ji->last_jobid, row[0], sizeof(ji->last_jobid));
    /* Concatenate a JobId if it does not exceed array size */
    if (strlen(ji->JobIds)+strlen(row[0])+2 < sizeof(ji->JobIds)) {
       if (ji->JobIds[0] != 0) {
index 6c95803decca7911baaab7e60ea609e8c901fd17..a09ffdff0df38e5abc5396042222ab2d94059dc3 100644 (file)
@@ -96,7 +96,7 @@ void user_select_files_from_tree(TREE_CTX *tree)
       }
       parse_ua_args(ua);
       if (ua->argc == 0) {
-        return;
+        break;
       }
 
       len = strlen(ua->argk[0]);
index 9ba836f3b61f7b35a7e644704dbb24798bfcdbdb..f0e3e2cb3296909adf84b06de71071b18803b33a 100644 (file)
@@ -87,150 +87,151 @@ struct JCR {
    /* Global part of JCR common to all daemons */
    JCR *next;
    JCR *prev;
-   volatile int use_count;           /* use count */
-   pthread_t my_thread_id;           /* id of thread controlling jcr */
-   pthread_mutex_t mutex;            /* jcr mutex */
-   BSOCK *dir_bsock;                 /* Director bsock or NULL if we are him */
-   BSOCK *store_bsock;               /* Storage connection socket */
-   BSOCK *file_bsock;                /* File daemon connection socket */
+   volatile int use_count;            /* use count */
+   pthread_t my_thread_id;            /* id of thread controlling jcr */
+   pthread_mutex_t mutex;             /* jcr mutex */
+   BSOCK *dir_bsock;                  /* Director bsock or NULL if we are him */
+   BSOCK *store_bsock;                /* Storage connection socket */
+   BSOCK *file_bsock;                 /* File daemon connection socket */
    JCR_free_HANDLER *daemon_free_jcr; /* Local free routine */
-   POOLMEM *errmsg;                  /* edited error message */
-   char Job[MAX_NAME_LENGTH];        /* Unique name of this Job */
+   POOLMEM *errmsg;                   /* edited error message */
+   char Job[MAX_NAME_LENGTH];         /* Unique name of this Job */
    uint32_t JobId;                    /* Director's JobId */
    uint32_t VolSessionId;
    uint32_t VolSessionTime;
-   uint32_t JobFiles;                /* Number of files written, this job */
-   uint32_t JobErrors;               /* */
-   uint64_t JobBytes;                /* Number of bytes processed this job */
-   uint64_t ReadBytes;               /* Bytes read -- before compression */
-   uint32_t Errors;                  /* Number of non-fatal errors */
-   volatile int JobStatus;           /* ready, running, blocked, terminated */ 
-   int JobType;                      /* backup, restore, verify ... */
-   int JobLevel;                     /* Job level */
-   int JobPriority;                  /* Job priority */
-   int authenticated;                /* set when client authenticated */
-   time_t sched_time;                /* job schedule time, i.e. when it should start */
-   time_t start_time;                /* when job actually started */
-   time_t run_time;                  /* used for computing speed */
-   time_t end_time;                  /* job end time */
-   POOLMEM *VolumeName;              /* Volume name desired -- pool_memory */
-   POOLMEM *client_name;             /* client name */
-   POOLMEM *RestoreBootstrap;        /* Bootstrap file to restore */
-   char *sd_auth_key;                /* SD auth key */
-   MSGS *jcr_msgs;                   /* Copy of message resource -- actually used */
-   uint32_t ClientId;                /* Client associated with Job */
-   char *where;                      /* prefix to restore files to */
-   int prefix_links;                 /* Prefix links with Where path */
-   int cached_pnl;                   /* cached path length */
-   POOLMEM *cached_path;             /* cached path */
+   uint32_t JobFiles;                 /* Number of files written, this job */
+   uint32_t JobErrors;                /* */
+   uint64_t JobBytes;                 /* Number of bytes processed this job */
+   uint64_t ReadBytes;                /* Bytes read -- before compression */
+   uint32_t Errors;                   /* Number of non-fatal errors */
+   volatile int JobStatus;            /* ready, running, blocked, terminated */ 
+   int JobType;                       /* backup, restore, verify ... */
+   int JobLevel;                      /* Job level */
+   int JobPriority;                   /* Job priority */
+   int authenticated;                 /* set when client authenticated */
+   time_t sched_time;                 /* job schedule time, i.e. when it should start */
+   time_t start_time;                 /* when job actually started */
+   time_t run_time;                   /* used for computing speed */
+   time_t end_time;                   /* job end time */
+   POOLMEM *VolumeName;               /* Volume name desired -- pool_memory */
+   POOLMEM *client_name;              /* client name */
+   POOLMEM *RestoreBootstrap;         /* Bootstrap file to restore */
+   char *sd_auth_key;                 /* SD auth key */
+   MSGS *jcr_msgs;                    /* Copy of message resource -- actually used */
+   uint32_t ClientId;                 /* Client associated with Job */
+   char *where;                       /* prefix to restore files to */
+   int prefix_links;                  /* Prefix links with Where path */
+   int cached_pnl;                    /* cached path length */
+   POOLMEM *cached_path;              /* cached path */
 
    /* Daemon specific part of JCR */
    /* This should be empty in the library */
 
 #ifdef DIRECTOR_DAEMON
    /* Director Daemon specific part of JCR */
-   pthread_t SD_msg_chan;            /* Message channel thread id */
-   pthread_cond_t term_wait;         /* Wait for job termination */
-   workq_ele_t *work_item;           /* Work queue item if scheduled */
+   pthread_t SD_msg_chan;             /* Message channel thread id */
+   pthread_cond_t term_wait;          /* Wait for job termination */
+   workq_ele_t *work_item;            /* Work queue item if scheduled */
    volatile bool sd_msg_thread_done;  /* Set when Storage message thread terms */
-   BSOCK *ua;                        /* User agent */
-   JOB *job;                         /* Job resource */
-   STORE *store;                     /* Storage resource */
-   CLIENT *client;                   /* Client resource */
-   POOL *pool;                       /* Pool resource */
-   FILESET *fileset;                 /* FileSet resource */
-   CAT *catalog;                     /* Catalog resource */
-   MSGS *messages;                   /* Default message handler */
-   uint32_t SDJobFiles;              /* Number of files written, this job */
-   uint64_t SDJobBytes;              /* Number of bytes processed this job */
-   uint32_t SDErrors;                /* Number of non-fatal errors */
-   volatile int SDJobStatus;         /* Storage Job Status */
-   volatile int FDJobStatus;         /* File daemon Job Status */
-   B_DB *db;                         /* database pointer */
-   uint32_t MediaId;                 /* DB record IDs associated with this job */
-   uint32_t PoolId;                  /* Pool record id */
-   FileId_t FileId;                  /* Last file id inserted */
-   uint32_t FileIndex;               /* Last FileIndex processed */
-   POOLMEM *fname;                   /* name to put into catalog */
-   int fn_printed;                   /* printed filename */
-   POOLMEM *stime;                   /* start time for incremental/differential */
-   JOB_DBR jr;                       /* Job record in Database */
-   uint32_t RestoreJobId;            /* Id specified by UA */
-   POOLMEM *client_uname;            /* client uname */ 
-   int replace;                      /* Replace option */
+   BSOCK *ua;                         /* User agent */
+   JOB *job;                          /* Job resource */
+   STORE *store;                      /* Storage resource */
+   CLIENT *client;                    /* Client resource */
+   POOL *pool;                        /* Pool resource */
+   FILESET *fileset;                  /* FileSet resource */
+   CAT *catalog;                      /* Catalog resource */
+   MSGS *messages;                    /* Default message handler */
+   uint32_t SDJobFiles;               /* Number of files written, this job */
+   uint64_t SDJobBytes;               /* Number of bytes processed this job */
+   uint32_t SDErrors;                 /* Number of non-fatal errors */
+   volatile int SDJobStatus;          /* Storage Job Status */
+   volatile int FDJobStatus;          /* File daemon Job Status */
+   B_DB *db;                          /* database pointer */
+   uint32_t MediaId;                  /* DB record IDs associated with this job */
+   uint32_t PoolId;                   /* Pool record id */
+   FileId_t FileId;                   /* Last file id inserted */
+   uint32_t FileIndex;                /* Last FileIndex processed */
+   POOLMEM *fname;                    /* name to put into catalog */
+   int fn_printed;                    /* printed filename */
+   POOLMEM *stime;                    /* start time for incremental/differential */
+   JOB_DBR jr;                        /* Job record in Database */
+   uint32_t RestoreJobId;             /* Id specified by UA */
+   POOLMEM *client_uname;             /* client uname */ 
+   int replace;                       /* Replace option */
    bool acquired_resource_locks;      /* set if resource locks acquired */
-   int NumVols;                      /* Number of Volume used in pool */
-   int reschedule_count;             /* Number of times rescheduled */
+   int NumVols;                       /* Number of Volume used in pool */
+   int reschedule_count;              /* Number of times rescheduled */
 #endif /* DIRECTOR_DAEMON */
 
 
 #ifdef FILE_DAEMON
    /* File Daemon specific part of JCR */
    uint32_t num_files_examined;       /* files examined this job */
-   POOLMEM *last_fname;              /* last file saved/verified */
+   POOLMEM *last_fname;               /* last file saved/verified */
    /*********FIXME********* add missing files and files to be retried */
-   int incremental;                  /* set if incremental for SINCE */
-   time_t mtime;                     /* begin time for SINCE */
-   int mtime_only;                   /* compare only mtime and not ctime as well */
-   int listing;                      /* job listing in estimate */
-   long Ticket;                      /* Ticket */
-   int save_level;                   /* save level */
-   char *big_buf;                    /* I/O buffer */
-   POOLMEM *compress_buf;            /* Compression buffer */
-   int32_t compress_buf_size;        /* Length of compression buffer */
-   int replace;                      /* Replace options */
-   int buf_size;                     /* length of buffer */
-   void *ff;                         /* Find Files packet */
+   int incremental;                   /* set if incremental for SINCE */
+   time_t mtime;                      /* begin time for SINCE */
+   int mtime_only;                    /* compare only mtime and not ctime as well */
+   int listing;                       /* job listing in estimate */
+   long Ticket;                       /* Ticket */
+   int save_level;                    /* save level */
+   char *big_buf;                     /* I/O buffer */
+   POOLMEM *compress_buf;             /* Compression buffer */
+   int32_t compress_buf_size;         /* Length of compression buffer */
+   int replace;                       /* Replace options */
+   int buf_size;                      /* length of buffer */
+   void *ff;                          /* Find Files packet */
    char stored_addr[MAX_NAME_LENGTH]; /* storage daemon address */
    uint32_t StartFile;
    uint32_t EndFile;
    uint32_t StartBlock;
    uint32_t EndBlock;
-   pthread_t heartbeat_id;           /* id of heartbeat thread */
-   volatile BSOCK *hb_bsock;         /* duped SD socket */
+   pthread_t heartbeat_id;            /* id of heartbeat thread */
+   volatile BSOCK *hb_bsock;          /* duped SD socket */
 #endif /* FILE_DAEMON */
 
 
 #ifdef STORAGE_DAEMON
    /* Storage Daemon specific part of JCR */
-   JCR *next_dev;                    /* next JCR attached to device */
-   JCR *prev_dev;                    /* previous JCR attached to device */
+   JCR *next_dev;                     /* next JCR attached to device */
+   JCR *prev_dev;                     /* previous JCR attached to device */
    pthread_cond_t job_start_wait;     /* Wait for FD to start Job */
    int type;
-   DEVRES *device;                   /* device to use */
-   VOLUME_CAT_INFO VolCatInfo;       /* Catalog info for desired volume */
-   POOLMEM *job_name;                /* base Job name (not unique) */
-   POOLMEM *fileset_name;            /* FileSet */
-   POOLMEM *fileset_md5;             /* MD5 for FileSet */
-   POOLMEM *pool_name;               /* pool to use */
-   POOLMEM *pool_type;               /* pool type to use */
-   POOLMEM *media_type;              /* media type */
-   POOLMEM *dev_name;                /* device name */
-   VOL_LIST *VolList;                /* list to read */
-   int32_t NumVolumes;               /* number of volumes used */
-   int32_t CurVolume;                /* current volume number */
-   int spool_attributes;             /* set if spooling attributes */
-   int no_attributes;                /* set if no attributes wanted */
-   int label_status;                 /* device volume label status */
-   int label_errors;                 /* count of label errors */
+   DEVRES *device;                    /* device to use */
+   VOLUME_CAT_INFO VolCatInfo;        /* Catalog info for desired volume */
+   POOLMEM *job_name;                 /* base Job name (not unique) */
+   POOLMEM *fileset_name;             /* FileSet */
+   POOLMEM *fileset_md5;              /* MD5 for FileSet */
+   POOLMEM *pool_name;                /* pool to use */
+   POOLMEM *pool_type;                /* pool type to use */
+   POOLMEM *media_type;               /* media type */
+   POOLMEM *dev_name;                 /* device name */
+   VOL_LIST *VolList;                 /* list to read */
+   int32_t NumVolumes;                /* number of volumes used */
+   int32_t CurVolume;                 /* current volume number */
+   int spool_attributes;              /* set if spooling attributes */
+   int no_attributes;                 /* set if no attributes wanted */
+   int label_status;                  /* device volume label status */
+   int label_errors;                  /* count of label errors */
    int session_opened;
-   DEV_RECORD rec;                   /* Read/Write record */
-   long Ticket;                      /* ticket for this job */
-   uint32_t VolFirstIndex;           /* First file index this Volume */
-   uint32_t VolLastIndex;            /* Last file index this Volume */
-   uint32_t FileIndex;               /* Current File Index */
-   uint32_t EndFile;                 /* End file written */
-   uint32_t StartFile;               /* Start write file */
-   uint32_t StartBlock;              /* Start write block */
-   uint32_t EndBlock;                /* Ending block written */
-   bool NewVol;                      /* set when new Volume mounted */
-   bool WroteVol;                    /* set when Volume written */
-   int CurVol;                       /* Current Volume count */
+   DEV_RECORD rec;                    /* Read/Write record */
+   long Ticket;                       /* ticket for this job */
+   uint32_t VolFirstIndex;            /* First file index this Volume */
+   uint32_t VolLastIndex;             /* Last file index this Volume */
+   uint32_t FileIndex;                /* Current File Index */
+   uint32_t EndFile;                  /* End file written */
+   uint32_t StartFile;                /* Start write file */
+   uint32_t StartBlock;               /* Start write block */
+   uint32_t EndBlock;                 /* Ending block written */
+   bool NewVol;                       /* set when new Volume mounted */
+   bool WroteVol;                     /* set when Volume written */
+   bool NewFile;                      /* set when EOF written */
+   int CurVol;                        /* Current Volume count */
 
-   uint32_t FileId;                  /* Last file id inserted */
+   uint32_t FileId;                   /* Last file id inserted */
 
    /* Parmaters for Open Read Session */
-   BSR *bsr;                         /* Bootstrap record -- has everything */
+   BSR *bsr;                          /* Bootstrap record -- has everything */
    uint32_t read_VolSessionId;
    uint32_t read_VolSessionTime;
    uint32_t read_StartFile;
index e0d37949393d3829d98eee29b6d75624e8e27a5d..a30b072d2cf53bf7a451c1468a7655911034f205 100755 (executable)
@@ -33,7 +33,7 @@
 #endif
 
 /*
- * This subrouting gets a big buffer.
+ * This subroutine gets a big buffer.
  */
 static void malloc_buf(TREE_ROOT *root, int size)
 {
@@ -306,7 +306,7 @@ void print_tree(char *path, TREE_NODE *tree)
    case TN_NEWDIR:
    case TN_DIR:
    case TN_DIR_NLS:
-      sprintf(buf, "%s/%s", path, tree->fname);
+      bsnprintf(buf, sizeof(buf), "%s/%s", path, tree->fname);
       print_tree(buf, tree->child);
       break;
    case TN_ROOT:
@@ -334,9 +334,9 @@ int tree_getpath(TREE_NODE *node, char *buf, int buf_size)
    if (node->type == TN_DIR_NLS && buf[0] == '/' && buf[1] == 0) {
       buf[0] = 0;   
    }
-   strcat(buf, node->fname);
+   bstrncat(buf, node->fname, buf_size);
    if (node->type != TN_FILE) {
-      strcat(buf, "/");
+      bstrncat(buf, "/", buf_size);
    }
    return 1;
 }
@@ -474,7 +474,7 @@ void FillDirectoryTree(char *path, TREE_ROOT *root, TREE_NODE *parent)
       if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
         continue;
       }
-      strcpy(file, dir->d_name);
+      bstrncpy(file, dir->d_name, sizeof(file));
       snprintf(pathbuf, MAXPATHLEN-1, "%s/%s", path, file);
       if (lstat(pathbuf, &statbuf) < 0) {
          printf("lstat() failed. ERR=%s\n", strerror(errno));
index 0138bbd32b35e9df01784c9a62a86118b3124801..fdd4b1f4d269800c333bd33fa894100618321ab9 100644 (file)
@@ -140,10 +140,20 @@ default_path:
    attach_jcr_to_device(dev, jcr);    /* attach jcr to device */
    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
       jcr->VolumeName, dev_name(dev));
-   if ((dev->state & ST_TAPE) && vol->start_file > 0) {
-      Dmsg1(200, "====== Got start_file = %d\n", vol->start_file);
-      Jmsg(jcr, M_INFO, 0, _("Forward spacing to file %d.\n"), vol->start_file);
-      fsf_dev(dev, vol->start_file);
+   if (jcr->bsr) {
+      BSR *bsr;
+
+      jcr->bsr->reposition = true;
+      bsr = find_next_bsr(jcr->bsr, dev);
+      if (bsr) {
+         Jmsg(jcr, M_INFO, 0, _("Forward spacing to file:block %u:%u.\n"), 
+           bsr->volfile->sfile, bsr->volblock->sblock);
+        reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock);
+      } else if ((dev->state & ST_TAPE) && vol->start_file > 0) {
+         Dmsg1(200, "====== Got start_file = %d\n", vol->start_file);
+         Jmsg(jcr, M_INFO, 0, _("Forward spacing to file %d.\n"), vol->start_file);
+        fsf_dev(dev, vol->start_file);
+      }
    }
 
 get_out:
@@ -277,7 +287,7 @@ int release_device(JCR *jcr, DEVICE *dev)
       dev->num_writers--;
       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
       if (dev->num_writers == 0) {
-        /* If we have fully acquired the tape */
+        /* If we are the only writer, write EOF after job */
         if (dev->state & ST_LABEL) {
             Dmsg0(100, "dir_create_jobmedia_record. Release\n");
            dir_create_jobmedia_record(jcr);
index ed517b08d2ff3fbfb2f877a05d52d138beafc9ec..6f058b4c4a0f7ddeb8bdb660f361a258629635e6 100644 (file)
@@ -102,7 +102,7 @@ int main (int argc, char *argv[])
       switch (ch) {
       case 'b':                    /* bootstrap file */
         bsr = parse_bsr(NULL, optarg);
-//      dump_bsr(bsr);
+//      dump_bsr(bsr, true);
         break;
 
       case 'c':                    /* specify config file */
index ef24940c48a977f979c7373cff2356426e6955aa..1ea2a85d1ce0ae218c023f30c4a82372d963111e 100644 (file)
@@ -282,8 +282,9 @@ int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
     * If a new volume has been mounted since our last write
     *  Create a JobMedia record for the previous volume written,
     *  and set new parameters to write this volume   
+    * The saem applies for if we are in a new file.
     */
-   if (jcr->NewVol) {
+   if (jcr->NewVol || jcr->NewFile) {
       /* Create a jobmedia record for this job */
       if (!dir_create_jobmedia_record(jcr)) {
          Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
@@ -292,7 +293,13 @@ int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
         unlock_device(dev);
         return 0;
       }
-      set_new_volume_parameters(jcr, dev);
+      if (jcr->NewVol) {
+        /* Note, setting a new volume also handles any pending new file */
+        set_new_volume_parameters(jcr, dev);
+        jcr->NewFile = false;        /* this handled for new file too */
+      } else {
+        set_new_file_parameters(jcr, dev);
+      }
    }
 
    if (!write_block_to_dev(jcr, dev, block)) {
@@ -377,20 +384,41 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       Jmsg(jcr, M_INFO, 0, _("User defined maximum volume capacity %s exceeded on device %s.\n"),
            edit_uint64(max_cap, ed1),  dev->dev_name);
       block->write_failed = true;
-      weof_dev(dev, 1);              /* end the tape */
-      weof_dev(dev, 1);              /* write second eof */
+      weof_dev(dev, 2);              /* end the tape */
       dev->state |= (ST_EOF | ST_EOT | ST_WEOT);
-      return 0;
+      return 0;   
    }
 
    /* Limit maximum File size on volume to user specified value */
    if (dev->state & ST_TAPE) {
       if ((dev->max_file_size > 0) && 
          (dev->file_addr+block->binbuf) >= dev->max_file_size) {
+
+        /* Write EOF */
         if (weof_dev(dev, 1) != 0) {            /* write eof */
             Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
-           /* Plunge on anyway -- if tape is bad we will die on write */
+           block->write_failed = true;
+           dev->state |= (ST_EOF | ST_EOT | ST_WEOT);
+           return 0;   
+        }
+
+        /* Do bookkeeping to handle EOF just written */
+        if (!dir_create_jobmedia_record(jcr)) {
+             Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+                 jcr->VolCatInfo.VolCatName, jcr->Job);
+            return 0;
+        }
+        /* 
+         * Walk through all attached jcrs indicating the file has changed   
+         */
+         Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
+        for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+           if (mjcr->JobId == 0) {
+              continue;                 /* ignore console */
+           }
+           mjcr->NewFile = true;
         }
+        set_new_file_parameters(jcr, dev);
       }
    }
 
@@ -544,6 +572,9 @@ int read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_bloc
    uint32_t BlockNumber;
    int retry = 0;
 
+   if (dev_state(dev, ST_EOT)) {
+      return 0;
+   }
    looping = 0;
    Dmsg1(100, "Full read() in read_block_from_device() len=%d\n",
         block->buf_len);
index 57d5e485b6da4af9cfe54707c6a5ac550459cd82..6d26549f71cf091775af918eb8563672eefeb274 100644 (file)
@@ -52,7 +52,6 @@ static JCR *jcr;
 static SESSION_LABEL sessrec;
 static uint32_t num_files = 0;
 static ATTR *attr;
-static int non_support_data = 0;
 
 #define CONFIG_FILE "bacula-sd.conf"
 char *configfile;
@@ -370,26 +369,26 @@ static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sess
    char *rtype;
    memset(sessrec, 0, sizeof(sessrec));
    switch (rec->FileIndex) {
-      case PRE_LABEL:
-         rtype = "Fresh Volume Label";   
-        break;
-      case VOL_LABEL:
-         rtype = "Volume Label";
-        unser_volume_label(dev, rec);
-        break;
-      case SOS_LABEL:
-         rtype = "Begin Session";
-        unser_session_label(sessrec, rec);
-        break;
-      case EOS_LABEL:
-         rtype = "End Session";
-        break;
-      case EOM_LABEL:
-         rtype = "End of Medium";
-        break;
-      default:
-         rtype = "Unknown";
-        break;
+   case PRE_LABEL:
+      rtype = "Fresh Volume Label";   
+      break;
+   case VOL_LABEL:
+      rtype = "Volume Label";
+      unser_volume_label(dev, rec);
+      break;
+   case SOS_LABEL:
+      rtype = "Begin Session";
+      unser_session_label(sessrec, rec);
+      break;
+   case EOS_LABEL:
+      rtype = "End Session";
+      break;
+   case EOM_LABEL:
+      rtype = "End of Medium";
+      break;
+   default:
+      rtype = "Unknown";
+      break;
    }
    Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
         rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
index 780ca3d0375b7d34e73453880ed5d8cf9c50c996..a75016ccbd616d301d38b282dd31f0cfb55eb36d 100644 (file)
@@ -38,7 +38,7 @@ struct VOL_LIST {
    VOL_LIST *next;
    char VolumeName[MAX_NAME_LENGTH];
    int Slot; 
-   int start_file;
+   uint32_t start_file;
 };
 
 
@@ -124,7 +124,10 @@ struct BSR_STREAM {
 
 struct BSR {
    BSR          *next;                /* pointer to next one */
-   bool          done;                /* set when everything found */
+   BSR          *root;                /* root bsr */
+   bool          reposition;          /* set when any bsr is marked done */
+   bool          mount_next_volume;   /* set when next volume should be mounted */
+   bool          done;                /* set when everything found for this bsr */
    bool          use_fast_rejection;  /* set if fast rejection can be used */
    bool          use_positioning;     /* set if we can position the archive */
    BSR_VOLUME   *volume;
index 91e42c47760a44fd0beae21f65c77bf988ec9f13..072b4e4c5b35cf137452fa2c29ab102fce1321a8 100644 (file)
@@ -139,7 +139,7 @@ int main(int argc, char *argv[])
       switch (ch) {
       case 'b':                    /* bootstrap file */
         bsr = parse_bsr(NULL, optarg);
-//      dump_bsr(bsr);
+//      dump_bsr(bsr, true);
         break;
 
       case 'c':                    /* specify config file */
@@ -809,10 +809,8 @@ static void fsfcmd()
 /* Forward space a record */
 static void fsrcmd()
 {
-   int stat;
-
-   if ((stat=fsr_dev(dev, 1)) < 0) {
-      Pmsg2(0, "Bad status from fsr %d. ERR=%s\n", stat, strerror_dev(dev));
+   if (!fsr_dev(dev, 1)) {
+      Pmsg1(0, "Bad status from fsr. ERR=%s\n", strerror_dev(dev));
       return;
    }
    Pmsg0(0, "Forward spaced one record.\n");
index 1994e23c1c290cb880029acf8cda4180615473bf..8f958576f765ed8fe4dd93ad0ea1019c1db45d21 100644 (file)
@@ -638,7 +638,7 @@ int offline_dev(DEVICE *dev)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, _("Bad call to load_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to offline_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return 0;
    }
@@ -809,6 +809,8 @@ fsf_dev(DEVICE *dev, int num)
 
 /* 
  * Backward space a file  
+ *  Returns: 0 on failure
+ *          1 on success
  */
 int
 bsf_dev(DEVICE *dev, int num)
@@ -818,12 +820,12 @@ bsf_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to bsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
-      return -1;
+      return 0;
    }
 
-   if (!(dev->state & ST_TAPE)) {
+   if (!(dev_state(dev, ST_TAPE))) {
       return 0;
    }
    Dmsg0(29, "bsf_dev\n");
@@ -839,12 +841,14 @@ bsf_dev(DEVICE *dev, int num)
         dev->dev_name, strerror(dev->dev_errno));
    }
    update_pos_dev(dev);
-   return stat;
+   return stat == 0 ? 1 : 0;
 }
 
 
 /* 
  * Foward space a record
+ *  Returns: 0 on failure
+ *          1 on success
  */
 int
 fsr_dev(DEVICE *dev, int num)
@@ -854,12 +858,12 @@ fsr_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to fsr_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
-      return -1;
+      return 0;
    }
 
-   if (!(dev->state & ST_TAPE)) {
+   if (!(dev_state(dev, ST_TAPE))) {
       return 0;
    }
    Dmsg0(29, "fsr_dev\n");
@@ -882,13 +886,13 @@ fsr_dev(DEVICE *dev, int num)
         dev->dev_name, strerror(dev->dev_errno));
    }
    update_pos_dev(dev);
-   return stat;
+   return stat == 0 ? 1 : 0;
 }
 
 /* 
  * Backward space a record
- *   Returns:  0 on success
- *           -1 on failure
+ *   Returns:  0 on failure
+ *            1 on success
  */
 int
 bsr_dev(DEVICE *dev, int num)
@@ -898,9 +902,9 @@ bsr_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to bsr_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
-      return -1;
+      return 0;
    }
 
    if (!(dev->state & ST_TAPE)) {
@@ -925,7 +929,49 @@ bsr_dev(DEVICE *dev, int num)
         dev->dev_name, strerror(dev->dev_errno));
    }
    update_pos_dev(dev);
-   return stat;
+   return stat == 0 ? 1 : 0;
+}
+
+/* 
+ * Reposition the device to file, block
+ *   Currently only works for tapes.
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int
+reposition_dev(DEVICE *dev, uint32_t file, uint32_t block)
+{ 
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, _("Bad call to reposition_dev. Archive not open\n"));
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return 0;
+   }
+
+   if (!(dev_state(dev, ST_TAPE))) {
+      return 0;
+   }
+   Dmsg4(100, "reposition_dev from %u:%u to %u:%u\n", 
+      dev->file, dev->block_num, file, block);
+   if (file < dev->file) {
+      Dmsg0(100, "Rewind_dev\n");
+      if (!rewind_dev(dev)) {
+        return 0;
+      }
+   }
+   if (file > dev->file) {
+      Dmsg1(100, "fsf %d\n", file-dev->file);
+      if (!fsf_dev(dev, file-dev->file)) {
+        return 0;
+      }
+   }
+   if (block > dev->block_num) {
+      /* Ignore errors as Bacula can read to the correct block */
+      Dmsg1(100, "fsr %d\n", block-dev->block_num);
+      fsr_dev(dev, block-dev->block_num);
+   }
+   return 1;
 }
 
 
@@ -943,7 +989,7 @@ weof_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to weof_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return -1;
    }
@@ -958,7 +1004,7 @@ weof_dev(DEVICE *dev, int num)
    mt_com.mt_count = num;
    stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
    if (stat == 0) {
-      dev->file++;
+      dev->file += num;
       dev->file_addr = 0;
    } else {
       clrerror_dev(dev, MTWEOF);
@@ -1099,7 +1145,7 @@ void
 close_dev(DEVICE *dev)
 {
    if (!dev) {
-      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to close_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return;
    }
@@ -1120,7 +1166,7 @@ close_dev(DEVICE *dev)
 void force_close_dev(DEVICE *dev)
 {
    if (!dev) {
-      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to force_close_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return;
    }
@@ -1200,7 +1246,7 @@ term_dev(DEVICE *dev)
 {
    if (!dev) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
+      Mmsg0(&dev->errmsg, _("Bad call to term_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return;
    }
index 70e7b9b8f1138a2afcc9ad9b04a394f95f35fc4c..797fa441b68dae7c631d65aa4c5c18cb0c70e753 100644 (file)
@@ -84,7 +84,7 @@
 #define CAP_BSFATEOM       (1<<15)    /* Backspace file at EOM */
 
 /* Test state */
-#define dev_state(dev, state) ((dev)->state & (state))
+#define dev_state(dev, st_state) ((dev)->state & (st_state))
 
 /* Device state bits */
 #define ST_OPENED          (1<<0)     /* set when device opened */
index 5e047de557803fe90b2f5cd57e4a6f2dc9ab9b76..525003555f492eb59e8106ea12d8d1bdaa0b8638 100644 (file)
@@ -216,6 +216,29 @@ void set_new_volume_parameters(JCR *jcr, DEVICE *dev)
    jcr->WroteVol = false;
 }
 
+/*
+ * We are now in a new file, so reset the Volume parameters
+ *  concerning this job.  The global changes were made earlier
+ *  in the dev structure.
+ */
+void set_new_file_parameters(JCR *jcr, DEVICE *dev) 
+{
+   /* Set new start/end positions */
+   if (dev->state & ST_TAPE) {
+      jcr->StartBlock = dev->block_num;
+      jcr->StartFile = dev->file;
+   } else {
+      jcr->StartBlock = (uint32_t)dev->file_addr;
+      jcr->StartFile  = (uint32_t)(dev->file_addr >> 32);
+   }
+   /* Reset indicies */
+   jcr->VolFirstIndex = 0;
+   jcr->VolLastIndex = 0;
+   jcr->NewFile = false;
+   jcr->WroteVol = false;
+}
+
+
 
 /*
  *   Open the device. Expect dev to already be initialized.  
index 0344b771443e41a3d7020d09579b1b52777d9f14..e4eaf9df49d51b9602847fabd8ed9ea899a49a39 100644 (file)
@@ -343,7 +343,7 @@ static int bootstrap_cmd(JCR *jcr)
       goto bail_out;
    }
    if (debug_level > 20) {
-      dump_bsr(jcr->bsr);
+      dump_bsr(jcr->bsr, true);
    }
    return bnet_fsend(fd, OK_bootstrap);
 
index 95fed69776de4b1a80d308b8937558f18cbe5ff1..d06cedd06c0cfaf8c5cf4ddc36647cbed915e24e 100755 (executable)
@@ -46,6 +46,8 @@ static int match_stream(BSR *bsr, BSR_STREAM *stream, DEV_RECORD *rec, bool done
 static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sessrec, bool done);
 static int match_block_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_BLOCK *block);
 static int match_block_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_BLOCK *block);
+static BSR *find_smallest_volfile(BSR *fbsr, BSR *bsr);
+
 
 /*********************************************************************
  *
@@ -114,22 +116,121 @@ static int match_block_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_BLOCK *block)
  *
  *     Match Bootstrap records
  *       returns  1 on match
- *       returns  0 no match
+ *       returns  0 no match and reposition is set if we should
+ *                     reposition the tape
  *      returns -1 no additional matches possible
  */
 int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sessrec)
 {
    int stat;
 
+   /*
+    * The bsr->reposition flag is set any time a bsr is done.
+    *  In this case, we can probably reposition the
+    *  tape to the next available bsr position.
+    */
    if (bsr) {
+      bsr->reposition = false;
       stat = match_all(bsr, rec, volrec, sessrec, true);
+      /* 
+       * Note, bsr->reposition is set by match_all when
+       *  a bsr is done. We turn it off if a match was
+       *  found or if we cannot use poistioning
+       */
+      if (stat != 0 || !bsr->use_positioning) {
+        bsr->reposition = false;
+      }
    } else {
-      stat = 0;
+      stat = 1;                      /* no bsr => match all */
    }
-// Dmsg1(000, "BSR returning %d\n", stat);
    return stat;
 }
 
+/*
+ * Find the next bsr that applies to the current tape.
+ *   It is the one with the smallest VolFile position.
+ */
+BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev)
+{
+   BSR *bsr;
+   BSR *found_bsr = NULL;
+
+   if (!root_bsr || !root_bsr->use_positioning || 
+       !root_bsr->reposition || !dev_is_tape(dev)) {
+      Dmsg2(000, "use_pos=%d repos=%d\n", root_bsr->use_positioning,
+       root_bsr->reposition);
+      return NULL;
+   }
+   root_bsr->mount_next_volume = false;
+   for (bsr=root_bsr; bsr; bsr=bsr->next) {
+      if (bsr->done || !match_volume(bsr, bsr->volume, &dev->VolHdr, 1)) {
+        continue;
+      }
+      if (found_bsr == NULL) {
+        found_bsr = bsr;
+      } else {
+        found_bsr = find_smallest_volfile(found_bsr, bsr);
+      }
+   }
+   /*
+    * If we get to this point and found no bsr, it means
+    *  that any additional bsr's must apply to the next
+    *  tape, so set a flag.
+    */
+   if (found_bsr == NULL) {
+      root_bsr->mount_next_volume = true;
+   }
+   return found_bsr;
+}
+
+static BSR *find_smallest_volfile(BSR *found_bsr, BSR *bsr)
+{
+   BSR *return_bsr = found_bsr;
+   BSR_VOLFILE *vf;
+   BSR_VOLBLOCK *vb;
+   uint32_t found_bsr_sfile, bsr_sfile;
+   uint32_t found_bsr_sblock, bsr_sblock;
+
+   vf = found_bsr->volfile;
+   found_bsr_sfile = vf->sfile;
+   while ( (vf=vf->next) ) {
+      if (vf->sfile < found_bsr_sfile) {
+        found_bsr_sfile = vf->sfile;
+      }
+   }
+   vf = bsr->volfile;
+   bsr_sfile = vf->sfile;
+   while ( (vf=vf->next) ) {
+      if (vf->sfile < bsr_sfile) {
+        bsr_sfile = vf->sfile;
+      }
+   }
+   if (found_bsr_sfile > bsr_sfile) {
+      return_bsr = bsr;
+   } else if (found_bsr_sfile == bsr_sfile) {
+      /* Must check block */
+      vb = found_bsr->volblock;
+      found_bsr_sblock = vb->sblock;
+      while ( (vb=vb->next) ) {
+        if (vb->sblock < found_bsr_sblock) {
+           found_bsr_sblock = vb->sblock;
+        }
+      }
+      vb = bsr->volblock;
+      bsr_sblock = vb->sblock;
+      while ( (vb=vb->next) ) {
+        if (vb->sblock < bsr_sblock) {
+           bsr_sblock = vb->sblock;
+        }
+      }
+      if (found_bsr_sblock > bsr_sblock) {
+        return_bsr = bsr;
+      }
+   }
+
+   return return_bsr;
+}
+
 /* 
  * Match all the components of current record
  *   returns  1 on match
@@ -144,6 +245,8 @@ static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
    }
    if (bsr->count && bsr->count <= bsr->found) {
       bsr->done = true;
+      bsr->root->reposition = true;
+      Dmsg0(100, "bsr done from count\n");
       goto no_match;
    }
    if (!match_volume(bsr, bsr->volume, volrec, 1)) {
@@ -305,6 +408,8 @@ static int match_volfile(BSR *bsr, BSR_VOLFILE *volfile, DEV_RECORD *rec, bool d
    /* If we are done and all prior matches are done, this bsr is finished */
    if (volfile->done && done) {
       bsr->done = true;
+      bsr->root->reposition = true;
+      Dmsg0(100, "bsr done from volfile\n");
    }
    return 0;
 }
@@ -339,6 +444,8 @@ static int match_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_RECORD *rec, boo
    }
    if (sesstime->done && done) {
       bsr->done = true;
+      bsr->root->reposition = true;
+      Dmsg0(100, "bsr done from sesstime\n");
    }
    return 0;
 }
@@ -373,6 +480,8 @@ static int match_findex(BSR *bsr, BSR_FINDEX *findex, DEV_RECORD *rec, bool done
    }
    if (findex->done && done) {
       bsr->done = true;
+      bsr->root->reposition = true;
+      Dmsg1(100, "bsr done from findex %d\n", rec->FileIndex);
    }
    return 0;
 }
index 6526424567dc19939761d34532cdd7aab08cae6b..83343dcb7a19c5b1ed118572f2ab7c6c6f1863a5 100755 (executable)
@@ -48,6 +48,7 @@ static BSR *store_exclude(LEX *lc, BSR *bsr);
 static BSR *store_stream(LEX *lc, BSR *bsr);
 static BSR *store_slot(LEX *lc, BSR *bsr);
 static bool is_fast_rejection_ok(BSR *bsr);
+static bool is_positioning_ok(BSR *bsr);
 
 struct kw_items {
    char *name;
@@ -81,7 +82,7 @@ struct kw_items items[] = {
 /* 
  * Create a BSR record
  */
-static BSR *new_bsr() 
+static BSR *new_bsr()
 {
    BSR *bsr = (BSR *)malloc(sizeof(BSR));
    memset(bsr, 0, sizeof(BSR));
@@ -118,15 +119,15 @@ static void s_err(char *file, int line, LEX *lc, char *msg, ...)
  *     Parse Bootstrap file
  *
  */
-BSR *parse_bsr(JCR *jcr, char *cf)
+BSR *parse_bsr(JCR *jcr, char *fname)
 {
    LEX *lc = NULL;
    int token, i;
    BSR *root_bsr = new_bsr();
    BSR *bsr = root_bsr;
-
-   Dmsg1(200, "Enter parse_bsf %s\n", cf);
-   lc = lex_open_file(lc, cf, s_err);
+     
+   Dmsg1(200, "Enter parse_bsf %s\n", fname);
+   lc = lex_open_file(lc, fname, s_err);
    lc->caller_ctx = (void *)jcr;
    while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
       Dmsg1(200, "parse got token=%s\n", lex_tok_to_str(token));
@@ -167,6 +168,10 @@ BSR *parse_bsr(JCR *jcr, char *cf)
    }
    if (root_bsr) {
       root_bsr->use_fast_rejection = is_fast_rejection_ok(root_bsr);
+      root_bsr->use_positioning = is_positioning_ok(root_bsr);
+   }
+   for (bsr=root_bsr; bsr; bsr=bsr->next) {
+      bsr->root = root_bsr;
    }
    return root_bsr;
 }
@@ -187,6 +192,22 @@ static bool is_fast_rejection_ok(BSR *bsr)
    return true;
 }
 
+static bool is_positioning_ok(BSR *bsr)
+{
+   /*
+    * Every bsr should have a volfile entry and a volblock entry
+    *  if we are going to use positioning
+    */
+   if (!bsr->volfile || !bsr->volblock) {
+      return false;
+   }
+   if (bsr->next) {
+      return is_positioning_ok(bsr->next);
+   }
+   return true;
+}
+
+
 static BSR *store_vol(LEX *lc, BSR *bsr)
 {
    int token;
@@ -667,14 +688,17 @@ void dump_sesstime(BSR_SESSTIME *sesstime)
 
 
 
-void dump_bsr(BSR *bsr)
+void dump_bsr(BSR *bsr, bool recurse)
 {
+   int save_debug = debug_level;
+   debug_level = 1;
    if (!bsr) {
       Dmsg0(-1, "BSR is NULL\n");
+      debug_level = save_debug;
       return;
    }
-   Dmsg1(-1,   
-"Next        : 0x%x\n", bsr->next);
+   Dmsg1(-1,    "Next        : 0x%x\n", bsr->next);
+   Dmsg1(-1,    "Root bsr    : 0x%x\n", bsr->root);
    dump_volume(bsr->volume);
    dump_sessid(bsr->sessid);
    dump_sesstime(bsr->sesstime);
@@ -690,10 +714,13 @@ void dump_bsr(BSR *bsr)
    if (bsr->count) {
       Dmsg1(-1, "count       : %u\n", bsr->count);
    }
-   if (bsr->next) {
+   Dmsg1(-1,    "done        : %s\n", bsr->done?"yes":"no");
+   Dmsg1(-1,    "positioning : %d\n", bsr->use_positioning);
+   if (recurse && bsr->next) {
       Dmsg0(-1, "\n");
-      dump_bsr(bsr->next);
+      dump_bsr(bsr->next, true);
    }
+   debug_level = save_debug;
 }
 
 
index be1116b9aa698ae3525f95cf55adb31b2254c4b3..20046490eb0fadf9ee625b69a1034b1a5ee6a5f5 100644 (file)
 uint32_t new_VolSessionId();
 
 /* From acquire.c */
-DEVICE  *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int      acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int      release_device(JCR *jcr, DEVICE *dev);
+DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     release_device(JCR *jcr, DEVICE *dev);
 
 /* From askdir.c */
 enum get_vol_info_rw {
    GET_VOL_INFO_FOR_WRITE,
    GET_VOL_INFO_FOR_READ
 };
-int     dir_get_volume_info(JCR *jcr, enum get_vol_info_rw);
-int     dir_find_next_appendable_volume(JCR *jcr);
-int     dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel);
-int     dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev);
-int     dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
-int     dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
-int     dir_send_job_status(JCR *jcr);
-int     dir_create_jobmedia_record(JCR *jcr);
+int    dir_get_volume_info(JCR *jcr, enum get_vol_info_rw);
+int    dir_find_next_appendable_volume(JCR *jcr);
+int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel);
+int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev);
+int    dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
+int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
+int    dir_send_job_status(JCR *jcr);
+int    dir_create_jobmedia_record(JCR *jcr);
 
 /* authenticate.c */
-int     authenticate_director(JCR *jcr);
-int     authenticate_filed(JCR *jcr);
+int    authenticate_director(JCR *jcr);
+int    authenticate_filed(JCR *jcr);
 
 /* From block.c */
-void    dump_block(DEV_BLOCK *b, char *msg);
+void   dump_block(DEV_BLOCK *b, char *msg);
 DEV_BLOCK *new_block(DEVICE *dev);
-void    init_block_write(DEV_BLOCK *block);
-void    empty_block(DEV_BLOCK *block);
-void    free_block(DEV_BLOCK *block);
-int     write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int     write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void   init_block_write(DEV_BLOCK *block);
+void   empty_block(DEV_BLOCK *block);
+void   free_block(DEV_BLOCK *block);
+int    write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int    write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
 
 #define CHECK_BLOCK_NUMBERS    true
 #define NO_BLOCK_NUMBER_CHECK  false
-int     read_block_from_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
-int     read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
+int    read_block_from_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
+int    read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
 
 /* From butil.c -- utilities for SD tool programs */
-void    print_ls_output(char *fname, char *link, int type, struct stat *statp);
+void   print_ls_output(char *fname, char *link, int type, struct stat *statp);
 JCR    *setup_jcr(char *name, char *device, BSR *bsr, char *VolumeName);
 DEVICE *setup_to_access_device(JCR *jcr, int read_access);
-void    display_tape_error_status(JCR *jcr, DEVICE *dev);
+void   display_tape_error_status(JCR *jcr, DEVICE *dev);
 DEVRES *find_device_res(char *device_name, int read_access);
 
 
 /* From dev.c */
-DEVICE  *init_dev(DEVICE *dev, DEVRES *device);
-int      open_dev(DEVICE *dev, char *VolName, int mode);
-void     close_dev(DEVICE *dev);
-void     force_close_dev(DEVICE *dev);
-int      truncate_dev(DEVICE *dev);
-void     term_dev(DEVICE *dev);
-char *   strerror_dev(DEVICE *dev);
-void     clrerror_dev(DEVICE *dev, int func);
-int      update_pos_dev(DEVICE *dev);
-int      rewind_dev(DEVICE *dev);
-int      load_dev(DEVICE *dev);
-int      offline_dev(DEVICE *dev);
-int      flush_dev(DEVICE *dev);
-int      weof_dev(DEVICE *dev, int num);
-int      write_block(DEVICE *dev);
-int      write_dev(DEVICE *dev, char *buf, size_t len);
-int      read_dev(DEVICE *dev, char *buf, size_t len);
-int      status_dev(DEVICE *dev, uint32_t *status);
-int      eod_dev(DEVICE *dev);
-int      fsf_dev(DEVICE *dev, int num);
-int      fsr_dev(DEVICE *dev, int num);
-int      bsf_dev(DEVICE *dev, int num);
-int      bsr_dev(DEVICE *dev, int num);
-void     attach_jcr_to_device(DEVICE *dev, JCR *jcr);
-void     detach_jcr_from_device(DEVICE *dev, JCR *jcr);
-JCR     *next_attached_jcr(DEVICE *dev, JCR *jcr);
-int     dev_can_write(DEVICE *dev);
-int     offline_or_rewind_dev(DEVICE *dev);
+DEVICE *init_dev(DEVICE *dev, DEVRES *device);
+int     open_dev(DEVICE *dev, char *VolName, int mode);
+void    close_dev(DEVICE *dev);
+void    force_close_dev(DEVICE *dev);
+int     truncate_dev(DEVICE *dev);
+void    term_dev(DEVICE *dev);
+char *  strerror_dev(DEVICE *dev);
+void    clrerror_dev(DEVICE *dev, int func);
+int     update_pos_dev(DEVICE *dev);
+int     rewind_dev(DEVICE *dev);
+int     load_dev(DEVICE *dev);
+int     offline_dev(DEVICE *dev);
+int     flush_dev(DEVICE *dev);
+int     weof_dev(DEVICE *dev, int num);
+int     write_block(DEVICE *dev);
+int     write_dev(DEVICE *dev, char *buf, size_t len);
+int     read_dev(DEVICE *dev, char *buf, size_t len);
+int     status_dev(DEVICE *dev, uint32_t *status);
+int     eod_dev(DEVICE *dev);
+int     fsf_dev(DEVICE *dev, int num);
+int     fsr_dev(DEVICE *dev, int num);
+int     bsf_dev(DEVICE *dev, int num);
+int     bsr_dev(DEVICE *dev, int num);
+void    attach_jcr_to_device(DEVICE *dev, JCR *jcr);
+void    detach_jcr_from_device(DEVICE *dev, JCR *jcr);
+JCR    *next_attached_jcr(DEVICE *dev, JCR *jcr);
+int     dev_can_write(DEVICE *dev);
+int     offline_or_rewind_dev(DEVICE *dev);
+int     reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
 
 
 /* Get info about device */
-char *   dev_name(DEVICE *dev);
-char *   dev_vol_name(DEVICE *dev);
+char *  dev_name(DEVICE *dev);
+char *  dev_vol_name(DEVICE *dev);
 uint32_t dev_block(DEVICE *dev);
 uint32_t dev_file(DEVICE *dev);
-int      dev_is_tape(DEVICE *dev);
+int     dev_is_tape(DEVICE *dev);
 
 /* From device.c */
-int      open_device(DEVICE *dev);
-int      fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     open_device(DEVICE *dev);
+int     fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
 void _lock_device(char *file, int line, DEVICE *dev);
 void _unlock_device(char *file, int line, DEVICE *dev);
 void _block_device(char *file, int line, DEVICE *dev, int state);
@@ -120,51 +121,53 @@ void _unblock_device(char *file, int line, DEVICE *dev);
 void _steal_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state);
 void _give_back_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold);
 void set_new_volume_parameters(JCR *jcr, DEVICE *dev);
+void set_new_file_parameters(JCR *jcr, DEVICE *dev); 
 
 /* From dircmd.c */
-void     *connection_request(void *arg); 
+void    *connection_request(void *arg); 
 
 
 /* From fd_cmds.c */
-void     run_job(JCR *jcr);
+void    run_job(JCR *jcr);
 
 /* From job.c */
-void     stored_free_jcr(JCR *jcr);
-void     connection_from_filed(void *arg);     
-void     handle_filed_connection(BSOCK *fd, char *job_name);
+void    stored_free_jcr(JCR *jcr);
+void    connection_from_filed(void *arg);     
+void    handle_filed_connection(BSOCK *fd, char *job_name);
 
 /* From label.c */
-int      read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void     create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
-void     create_volume_label(DEVICE *dev, char *VolName);
-int      write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
-int      write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
-int      write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void     dump_volume_label(DEVICE *dev);
-void     dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
-int      unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
-int      unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
+int     read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
+void    create_volume_label(DEVICE *dev, char *VolName);
+int     write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
+int     write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
+int     write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    dump_volume_label(DEVICE *dev);
+void    dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
+int     unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
+int     unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
 
 /* From match_bsr.c */
 int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, 
-              SESSION_LABEL *sesrec);
+             SESSION_LABEL *sesrec);
 int match_bsr_block(BSR *bsr, DEV_BLOCK *block);
 void position_bsr_block(BSR *bsr, DEV_BLOCK *block);
+BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev);
 
 /* From mount.c */
-int      mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
-int      mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void     release_volume(JCR *jcr, DEVICE *dev);
+int     mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
+int     mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    release_volume(JCR *jcr, DEVICE *dev);
 
 /* From autochanger.c */
-int      autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
-int      autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
-void     invalidate_slot_in_catalog(JCR *jcr);
+int     autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
+int     autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
+void    invalidate_slot_in_catalog(JCR *jcr);
 
 
 /* From parse_bsr.c */
 extern BSR *parse_bsr(JCR *jcr, char *lf);
-extern void dump_bsr(BSR *bsr);
+void dump_bsr(BSR *bsr, bool recurse);
 extern void free_bsr(BSR *bsr);
 extern VOL_LIST *new_vol();
 extern int add_vol(JCR *jcr, VOL_LIST *vol);
@@ -174,11 +177,11 @@ extern void create_vol_list(JCR *jcr);
 /* From record.c */
 char   *FI_to_ascii(int fi);
 char   *stream_to_ascii(int stream, int fi);
-int     write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int     can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int     read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); 
+int    write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int    can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int    read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); 
 DEV_RECORD *new_record();
-void    free_record(DEV_RECORD *rec);
+void   free_record(DEV_RECORD *rec);
 
 /* From read_record.c */
 int read_records(JCR *jcr,  DEVICE *dev, 
index 0d10941c6a5e48a017a70689fc63cc7647afe9db..a555a6a6646f0d1ec064fa97af7e2339c3aa3a4a 100644 (file)
@@ -48,7 +48,7 @@ int read_records(JCR *jcr,  DEVICE *dev,
    int ok = TRUE;
    bool done = false;
    SESSION_LABEL sessrec;
-   dlist *recs;                        
+   dlist *recs;                        /* linked list of rec packets open */
 
    block = new_block(dev);
    recs = new dlist(rec, &rec->link);
@@ -60,7 +60,7 @@ int read_records(JCR *jcr,  DEVICE *dev,
       }
       if (!read_block_from_device(jcr, dev, block, CHECK_BLOCK_NUMBERS)) {
          Dmsg0(20, "!read_record()\n");
-        if (dev->state & ST_EOT) {
+        if (dev_state(dev, ST_EOT)) {
            DEV_RECORD *trec = new_record();
 
             Dmsg3(100, "EOT. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
@@ -96,12 +96,28 @@ int read_records(JCR *jcr,  DEVICE *dev,
            get_session_record(dev, trec, &sessrec);
            ok = record_cb(jcr, dev, block, trec);
            free_record(trec);
-        } else if (dev->state & ST_EOF) {
+           /*
+            * Now find and position to first file and block 
+            *   on this tape.
+            */
+           BSR *bsr = find_next_bsr(jcr->bsr, dev);
+           if (bsr == NULL && jcr->bsr->mount_next_volume) {
+               Dmsg0(100, "Would mount next volume here\n");
+           }     
+           if (bsr) {
+               Dmsg4(100, "Reposition new tape from (file:block) %d:%d to %d:%d\n",
+                 dev->file, dev->block_num, bsr->volfile->sfile,
+                 bsr->volblock->sblock);
+              reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock);
+               Dmsg2(100, "Now at (file:block) %d:%d\n",
+                 dev->file, dev->block_num);
+           }
+        } else if (dev_state(dev, ST_EOF)) {
             Jmsg(jcr, M_INFO, 0, "Got EOF at file %u  on device %s, Volume \"%s\"\n", 
                  dev->file, dev_name(dev), jcr->VolumeName);
             Dmsg0(20, "read_record got eof. try again\n");
            continue;
-        } else if (dev->state & ST_SHORT) {
+        } else if (dev_state(dev, ST_SHORT)) {
             Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
            continue;
         } else {
@@ -111,8 +127,10 @@ int read_records(JCR *jcr,  DEVICE *dev,
            break;
         }
       }
+      Dmsg5(100, "Read block: dev=%d blk=%d VI=%u VT=%u blen=%d\n", dev->block_num, block->BlockNumber, 
+        block->VolSessionId, block->VolSessionTime, block->block_len);
       if (!match_bsr_block(jcr->bsr, block)) {
-         Dmsg5(150, "reject Blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n",
+         Dmsg5(100, "reject Blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n",
            block->BlockNumber, block->block_len, block->BlockVer,
            block->VolSessionId, block->VolSessionTime);
         continue;
@@ -138,7 +156,7 @@ int read_records(JCR *jcr,  DEVICE *dev,
          Dmsg2(100, "New record for SI=%d ST=%d\n",
             block->VolSessionId, block->VolSessionTime);
       } else {
-        if ((rec->Block+1) != block->BlockNumber) {
+        if (rec->Block != 0 && (rec->Block+1) != block->BlockNumber) {
             Jmsg(jcr, M_ERROR, 0, _("Invalid block number. Expected %u, got %u\n"),
                 rec->Block+1, block->BlockNumber);
         }
@@ -150,8 +168,9 @@ int read_records(JCR *jcr,  DEVICE *dev,
                  block->BlockNumber, rec->remainder);
            break;
         }
-         Dmsg3(10, "read-OK. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), 
-                 block->BlockNumber, rec->remainder);
+         Dmsg5(100, "read-OK. stat=%s blk=%d rem=%d file:block=%d:%d\n", 
+                rec_state_to_str(rec), block->BlockNumber, rec->remainder,
+                dev->file, dev->block_num);
         /*
          * At this point, we have at least a record header.
          *  Now decide if we want this record or not, but remember
@@ -159,7 +178,7 @@ int read_records(JCR *jcr,  DEVICE *dev,
          *  get all the data.
          */
         record++;
-         Dmsg6(30, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
+         Dmsg6(100, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
            rec_state_to_str(rec), block->BlockNumber,
            rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
          Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
@@ -194,6 +213,25 @@ int read_records(JCR *jcr,  DEVICE *dev,
               done = true;   /* all items found, stop */
               break;
            } else if (stat == 0) {  /* no match */
+              BSR *bsr;
+              bsr = find_next_bsr(jcr->bsr, dev);
+              if (bsr == NULL && jcr->bsr->mount_next_volume) {
+                  Dmsg0(100, "Would mount next volume here\n");
+                  Dmsg2(100, "Current postion (file:block) %d:%d\n",
+                    dev->file, dev->block_num);
+                 dev->state |= ST_EOT;
+                 rec->Block = 0;
+                 break;
+              }     
+              if (bsr) {
+                  Dmsg4(100, "Reposition from (file:block) %d:%d to %d:%d\n",
+                    dev->file, dev->block_num, bsr->volfile->sfile,
+                    bsr->volblock->sblock);
+                 reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock);
+                 rec->Block = 0;
+                  Dmsg2(100, "Now at (file:block) %d:%d\n",
+                    dev->file, dev->block_num);
+              }
                Dmsg5(10, "BSR no match rec=%d block=%d SessId=%d SessTime=%d FI=%d\n",
                  record, block->BlockNumber, rec->VolSessionId, rec->VolSessionTime, 
                  rec->FileIndex);