From: Kern Sibbald Date: Sun, 31 Aug 2003 10:29:36 +0000 (+0000) Subject: Implement repositioning code + misc X-Git-Tag: Release-7.0.0~10016 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=aa8412d6fbde9fca6621a6631e9ab8b1cbbdba26;p=bacula%2Fbacula Implement repositioning code + misc git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@680 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index 040852203f..c6d646a1a5 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -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 + 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 diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 9d8875e8f1..1406ca4dfb 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -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"); diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index 7a29ac141b..c0379235f8 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -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); diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 285558286c..7ff3a44fe6 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -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; diff --git a/bacula/src/console.glade b/bacula/src/console.glade index 08f3d57563..c9509b3c36 100644 --- a/bacula/src/console.glade +++ b/bacula/src/console.glade @@ -18,6 +18,8 @@ GtkWindow app1 + 800 + 500 delete_event on_app1_delete_event @@ -27,7 +29,6 @@ GTK_WINDOW_TOPLEVEL GTK_WIN_POS_CENTER False - 800 500 True True diff --git a/bacula/src/dird/query.sql b/bacula/src/dird/query.sql index 61ecdc4c3c..3ef1a80cf1 100644 --- a/bacula/src/dird/query.sql +++ b/bacula/src/dird/query.sql @@ -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, diff --git a/bacula/src/dird/sql_cmds.c b/bacula/src/dird/sql_cmds.c index 1a9ae7a25e..6f78624a13 100644 --- a/bacula/src/dird/sql_cmds.c +++ b/bacula/src/dird/sql_cmds.c @@ -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 !!!!! */ diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index fa13461724..3ffffe1ef2 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -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) { diff --git a/bacula/src/dird/ua_tree.c b/bacula/src/dird/ua_tree.c index 6c95803dec..a09ffdff0d 100644 --- a/bacula/src/dird/ua_tree.c +++ b/bacula/src/dird/ua_tree.c @@ -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]); diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 9ba836f3b6..f0e3e2cb32 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -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; diff --git a/bacula/src/lib/tree.c b/bacula/src/lib/tree.c index e0d3794939..a30b072d2c 100755 --- a/bacula/src/lib/tree.c +++ b/bacula/src/lib/tree.c @@ -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)); diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index 0138bbd32b..fdd4b1f4d2 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -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); diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c index ed517b08d2..6f058b4c4a 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -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 */ diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index ef24940c48..1ea2a85d1c 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -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); diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index 57d5e485b6..6d26549f71 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -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); diff --git a/bacula/src/stored/bsr.h b/bacula/src/stored/bsr.h index 780ca3d037..a75016ccbd 100644 --- a/bacula/src/stored/bsr.h +++ b/bacula/src/stored/bsr.h @@ -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; diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index 91e42c4776..072b4e4c5b 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -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"); diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 1994e23c1c..8f958576f7 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -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; } diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 70e7b9b8f1..797fa441b6 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -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 */ diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index 5e047de557..525003555f 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -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. diff --git a/bacula/src/stored/fd_cmds.c b/bacula/src/stored/fd_cmds.c index 0344b77144..e4eaf9df49 100644 --- a/bacula/src/stored/fd_cmds.c +++ b/bacula/src/stored/fd_cmds.c @@ -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); diff --git a/bacula/src/stored/match_bsr.c b/bacula/src/stored/match_bsr.c index 95fed69776..d06cedd06c 100755 --- a/bacula/src/stored/match_bsr.c +++ b/bacula/src/stored/match_bsr.c @@ -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; } diff --git a/bacula/src/stored/parse_bsr.c b/bacula/src/stored/parse_bsr.c index 6526424567..83343dcb7a 100755 --- a/bacula/src/stored/parse_bsr.c +++ b/bacula/src/stored/parse_bsr.c @@ -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; } diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index be1116b9aa..20046490eb 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -28,91 +28,92 @@ 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, diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c index 0d10941c6a..a555a6a664 100644 --- a/bacula/src/stored/read_record.c +++ b/bacula/src/stored/read_record.c @@ -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);