From f2dfd500c0acf5ec87f363bc40cddf51b1c1ba7c Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 20 Feb 2006 20:04:01 +0000 Subject: [PATCH] 20Feb06 - Note. Your database must be updated, or you must create a new database. I have not yet incremented the database level. - Add Location table. - Add LocationId, DeviceId, and MediaTypeId to Media record. 18Feb06 - Implement create/get mac record in database for adding extended Migration data to the job record. - Add new MAC table to update/make database scripts. - Return Storage name used when getting VolumeNames for a job. - Change bsr file keyword Storage to Device, which is more accurate. - Ensure that Mac records are pruned/purged. - Tweak SD tools to deal with changing media type. - Integrate more dev.c subroutines as methods (e.g. strerror, bsr, ...) - Pass pointer to dcr pointer to acquire_device_for_read() so that the subroutine can switch devices, and hence dcrs. - Modify the multiple MediaType read code to re-use the same dcr when switching devices. This makes the code much more robust. - Integrate patch from Karl Hakimian that reads JobIds, FileIndexes from a table for restore. - Add Storage name to VolParams, but it really should be Device. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2794 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/kernstodo | 6 +- bacula/kes-1.39 | 22 ++ bacula/patches/dvd+rw-tools-6.1.bacula.patch | 85 +++++++ bacula/src/cats/cats.h | 31 +++ bacula/src/cats/make_mysql_tables.in | 16 ++ bacula/src/cats/make_postgresql_tables.in | 16 ++ bacula/src/cats/make_sqlite3_tables.in | 17 +- bacula/src/cats/make_sqlite_tables.in | 16 ++ bacula/src/cats/protos.h | 6 +- bacula/src/cats/sql_create.c | 72 +++++- bacula/src/cats/sql_get.c | 76 +++++- bacula/src/cats/update_mysql_tables.in | 93 ++----- bacula/src/cats/update_postgresql_tables.in | 134 ++-------- bacula/src/cats/update_sqlite3_tables.in | 250 +++---------------- bacula/src/cats/update_sqlite_tables.in | 250 +++---------------- bacula/src/dird/bsr.c | 36 ++- bacula/src/dird/mac.c | 13 +- bacula/src/dird/sql_cmds.c | 4 + bacula/src/dird/ua_cmds.c | 6 +- bacula/src/dird/ua_purge.c | 6 + bacula/src/dird/ua_restore.c | 56 ++++- bacula/src/stored/Makefile.in | 35 +-- bacula/src/stored/acquire.c | 118 ++++++--- bacula/src/stored/append.c | 10 +- bacula/src/stored/bcopy.c | 19 +- bacula/src/stored/bextract.c | 5 +- bacula/src/stored/block.c | 14 +- bacula/src/stored/bls.c | 5 +- bacula/src/stored/bscan.c | 5 +- bacula/src/stored/bsr.h | 4 +- bacula/src/stored/btape.c | 92 ++++--- bacula/src/stored/butil.c | 1 + bacula/src/stored/dev.c | 181 ++++++-------- bacula/src/stored/dev.h | 6 +- bacula/src/stored/device.c | 4 +- bacula/src/stored/dircmd.c | 10 +- bacula/src/stored/dvd.c | 2 +- bacula/src/stored/label.c | 18 +- bacula/src/stored/mac.c | 6 +- bacula/src/stored/mount.c | 2 +- bacula/src/stored/parse_bsr.c | 20 +- bacula/src/stored/protos.h | 6 +- bacula/src/stored/read.c | 2 +- bacula/src/stored/read_record.c | 9 +- bacula/src/stored/reserve.c | 34 ++- bacula/src/stored/reserve.h | 1 + bacula/src/stored/spool.c | 2 +- bacula/src/stored/stored.c | 5 +- bacula/src/version.h | 4 +- 49 files changed, 884 insertions(+), 947 deletions(-) create mode 100644 bacula/patches/dvd+rw-tools-6.1.bacula.patch diff --git a/bacula/kernstodo b/bacula/kernstodo index df9fc31983..45a1ce7c33 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 08 February 2006 + 17 February 2006 Major development: Project Developer @@ -20,6 +20,9 @@ Priority: directive). For 1.39: +- Keep same dcr when switching device ... +- Job retention period in a Pool (and hence Volume). The job would + then be migrated. - Detect resource deadlock in Migrate when same job wants to read and write the same device. - Make hardlink code at line 240 of find_one.c use binary search. @@ -1280,4 +1283,3 @@ Block Position: 0 even defined). - Make sure Maximum Volumes is respected in Pools when adding Volumes (e.g. when pulling a Scratch volume). - diff --git a/bacula/kes-1.39 b/bacula/kes-1.39 index 9e3c3d8711..7c254d3546 100644 --- a/bacula/kes-1.39 +++ b/bacula/kes-1.39 @@ -4,6 +4,28 @@ General: Changes to 1.39.5 +20Feb06 +- Note!!! Your database must be updated, or you must create + a new database. I have not yet incremented the database level. +- Add Location table. +- Add LocationId, DeviceId, and MediaTypeId to Media record. +18Feb06 +- Implement create/get mac record in database for adding extended + Migration data to the job record. +- Add new MAC table to update/make database scripts. +- Return Storage name used when getting VolumeNames for a job. +- Change bsr file keyword Storage to Device, which is more accurate. +- Ensure that Mac records are pruned/purged. +- Tweak SD tools to deal with changing media type. +- Integrate more dev.c subroutines as methods (e.g. strerror, bsr, ...) +- Pass pointer to dcr pointer to acquire_device_for_read() so + that the subroutine can switch devices, and hence dcrs. +- Modify the multiple MediaType read code to re-use the same + dcr when switching devices. This makes the code much more + robust. +- Integrate patch from Karl Hakimian that reads JobIds, FileIndexes + from a table for restore. +- Add Storage name to VolParams, but it really should be Device. 14Feb06 - Add disk-changer to scripts directory + configure/Makefile - Eliminate PoolId from jcr -- it is in jcr->jr.PoolId diff --git a/bacula/patches/dvd+rw-tools-6.1.bacula.patch b/bacula/patches/dvd+rw-tools-6.1.bacula.patch new file mode 100644 index 0000000000..6785f7fb71 --- /dev/null +++ b/bacula/patches/dvd+rw-tools-6.1.bacula.patch @@ -0,0 +1,85 @@ +--- dvd+rw-tools-6.1.old/growisofs.c 2006-01-26 22:16:54.000000000 +0100 ++++ dvd+rw-tools-6.1/growisofs.c 2006-02-15 00:00:44.000000000 +0100 +@@ -355,12 +355,17 @@ + * - Treat only x73xx OPC errors as fatal; + * - Fix typo in -speed scaling code; + * - permit tracksize to be not divisible by 32KB in DAO mode; ++ * 6.1.1: (by Nicolas Boichat, Bacula project) ++ * - Allow session to cross 4GB boundary regardless of medium type ++ * (don't need to have a DL media) ++ * - Add a -F option (used instead of -M or -Z), which displays next_session ++ * offset and capacity (free space = next_session - capacity). + */ + #define PRINT_VERSION(cmd) do { \ + char *s=strrchr((cmd),'/'); \ + s ? s++ : (s=(cmd)); \ + printf ("* %.*sgrowisofs by ,"\ +- " version 6.1,\n",(int)(s-(cmd)),(cmd)); \ ++ " version 6.1.1,\n",(int)(s-(cmd)),(cmd)); \ + } while (0) + + #define _LARGEFILE_SOURCE +@@ -2329,6 +2334,18 @@ + else in_device = argv[++i]; + dev_found = 'Z'; + } ++ else if (argv[i][1] == 'F') ++ { if (len > 2) in_device = argv[i]+2; ++ else in_device = argv[++i]; ++ dev_found = 'F'; ++ dry_run = 1; /* NEVER write anything with -F */ ++ } ++ else if (!strncmp(opt,"-free-space",11)) ++ { if (len > 11) in_device = opt+11; ++ else in_device = argv[++i]; ++ dev_found = 'F'; ++ dry_run = 1; /* NEVER write anything with -F */ ++ } + else if (!strcmp(opt,"-poor-man")) + { if (poor_man<0) poor_man = 1; + continue; +@@ -2542,7 +2559,9 @@ + fprintf (stderr," you most likely want to use -Z option.\n"), + exit (FATAL_START(errno)); + +- if (dev_found == 'M') ++ if ((dev_found == 'M') || ++ ((dev_found == 'F') && !(mmc_profile&0x10000)) && (saved_descriptors[0].type[0] || saved_descriptors[0].type[1] || saved_descriptors[0].type[2])) ++ /* -F : The medium is not blank, there is a fs on it (the_buffer[0,1 or 2] != 0), so compute next_session. */ + { if (memcmp (saved_descriptors[0].type,"\1CD001",6)) + fprintf (stderr,":-( %s doesn't look like isofs...\n", + in_device), exit(FATAL_START(EMEDIUMTYPE)); +@@ -2565,7 +2584,7 @@ + exit(FATAL_START(EINVAL)); + } + else if (next_session > (0x200000-0x5000)) /* 4GB/2K-40MB/2K */ +- if ((mmc_profile&0xFFFF)!=0x2B || !no_4gb_check) ++ if (!no_4gb_check) + fprintf (stderr,":-( next session would cross 4GB " + "boundary, aborting...\n"), + exit (FATAL_START(ENOSPC)); +@@ -2608,7 +2627,7 @@ + exit (FATAL_START(EINVAL)); + + if (imgfd<0) +- { if (mkisofs_argc==1) ++ { if ((mkisofs_argc==1) && (dev_found != 'F')) + fprintf (stderr,"%s: no mkisofs options specified, " + "aborting...\n",argv[0]), + exit (FATAL_START(EINVAL)); +@@ -2880,6 +2899,15 @@ + } + } + ++ if (dev_found == 'F') { ++ off64_t capacity = 0; ++ printf("next_session=%lld\n", next_session*CD_BLOCK); ++ if (ioctl_handle!=INVALID_HANDLE) ++ capacity = get_capacity (ioctl_handle); ++ printf("capacity=%lld\n", capacity); ++ exit(0); ++ } ++ + if (imgfd>=0) + { quiet--; + if (builtin_dd (imgfd,out_fd,next_session*CD_BLOCK) < 0) diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index 12e7a9b3be..25d5b53ea4 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -546,6 +546,8 @@ struct JOB_DBR { uint32_t JobErrors; uint32_t JobMissingFiles; uint64_t JobBytes; + int PurgedFiles; + int HasBase; /* Note, FirstIndex, LastIndex, Start/End File and Block * are only used in the JobMedia record. @@ -565,6 +567,33 @@ struct JOB_DBR { faddr_t rec_addr; }; +/* + * Suplementary record for Migration, archive, copy jobs + */ +/* MAC record */ +struct MAC_DBR { + JobId_t JobId; /* Id of this job */ + JobId_t OriginalJobId; /* Id of job migrated, copied or archived */ + /* + * The following are the actual values for this job. This + * is needed because the values in the corresponding Job + * record were set to the values of the original backup job. + */ + int JobType; /* Actual job type */ + int JobLevel; /* Actual job level */ + time_t SchedTime; /* Actual time job scheduled */ + time_t StartTime; /* Actual Job start time */ + time_t EndTime; /* Actual Job termination time */ + utime_t JobTDate; /* Actual Backup time/date in seconds */ + + char cSchedTime[MAX_TIME_LENGTH]; + char cStartTime[MAX_TIME_LENGTH]; + char cEndTime[MAX_TIME_LENGTH]; + +}; + + + /* Job Media information used to create the media records * for each Volume used for the job. */ @@ -588,6 +617,7 @@ struct JOBMEDIA_DBR { struct VOL_PARAMS { char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ char MediaType[MAX_NAME_LENGTH]; /* Media Type */ + char Storage[MAX_NAME_LENGTH]; /* Storage name */ uint32_t VolIndex; /* Volume seqence no. */ uint32_t FirstIndex; /* First index this Volume */ uint32_t LastIndex; /* Last index this Volume */ @@ -595,6 +625,7 @@ struct VOL_PARAMS { uint32_t EndFile; /* End file on Volume */ uint32_t StartBlock; /* start block on tape */ uint32_t EndBlock; /* last block */ + int32_t Slot; /* Slot */ // uint32_t Copy; /* identical copy */ // uint32_t Stripe; /* RAIT strip number */ }; diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in index ca4fb29f96..7e4aeae7b8 100644 --- a/bacula/src/cats/make_mysql_tables.in +++ b/bacula/src/cats/make_mysql_tables.in @@ -112,6 +112,19 @@ CREATE TABLE Job ( INDEX (Name(128)) ); +CREATE TABLE MAC ( + JobId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + OriginalJobId INTEGER UNSIGNED NOT NULL, + JobType BINARY(1) NOT NULL, + JobLevel BINARY(1) NOT NULL, + SchedTime DATETIME NOT NULL, + StartTime DATETIME NOT NULL, + EndTime DATETIME NOT NULL, + JobTDate BIGINT UNSIGNED NOT NULL, + PRIMARY KEY(JobId) + ); + + # CREATE TABLE FileSet ( FileSetId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, @@ -145,6 +158,7 @@ CREATE TABLE Media ( Slot INTEGER NOT NULL DEFAULT 0, PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool, MediaType TINYBLOB NOT NULL, + MediaTypeId INTEGER UNSIGNED NOT NULL REFERENCES MediaType, LabelType TINYINT NOT NULL DEFAULT 0, FirstWritten DATETIME NOT NULL, LastWritten DATETIME NOT NULL, @@ -168,11 +182,13 @@ CREATE TABLE Media ( MaxVolBytes BIGINT UNSIGNED NOT NULL DEFAULT 0, InChanger TINYINT NOT NULL DEFAULT 0, StorageId INTEGER UNSIGNED NOT NULL REFERENCES Storage, + DeviceId INTEGER UNSIGNED NOT NULL REFERENCES Device, MediaAddressing TINYINT NOT NULL DEFAULT 0, VolReadTime BIGINT UNSIGNED NOT NULL DEFAULT 0, VolWriteTime BIGINT UNSIGNED NOT NULL DEFAULT 0, EndFile INTEGER UNSIGNED NOT NULL DEFAULT 0, EndBlock INTEGER UNSIGNED NOT NULL DEFAULT 0, + LocationId INTEGER UNSIGNED NOT NULL REFERENCES Location, PRIMARY KEY(MediaId), INDEX (PoolId) ); diff --git a/bacula/src/cats/make_postgresql_tables.in b/bacula/src/cats/make_postgresql_tables.in index be0e9f5840..cf13ce7317 100644 --- a/bacula/src/cats/make_postgresql_tables.in +++ b/bacula/src/cats/make_postgresql_tables.in @@ -76,6 +76,19 @@ CREATE TABLE job CREATE INDEX job_name_idx on job (name); +CREATE TABLE MAC ( + JobId serial not null, + OriginalJobId serial not null, + JobType char(1) not null, + JobLevel char(1) not null, + schedtime timestamp without time zone not null, + starttime timestamp without time zone, + endtime timestamp without time zone, + jobtdate bigint not null, + primary key (jobid) +); + + CREATE TABLE fileset ( filesetid serial not null, @@ -113,6 +126,7 @@ CREATE TABLE media slot integer not null default 0, poolid integer not null, mediatype text not null, + mediatypeid integer not null, labeltype integer not null default 0, firstwritten timestamp without time zone, lastwritten timestamp without time zone, @@ -138,11 +152,13 @@ CREATE TABLE media maxvolbytes bigint not null default 0, inchanger smallint not null default 0, StorageId integer default 0, + DeviceId integer default 0, mediaaddressing smallint not null default 0, volreadtime bigint not null default 0, volwritetime bigint not null default 0, endfile integer not null default 0, endblock bigint not null default 0, + LocationId integer default 0, primary key (mediaid) ); diff --git a/bacula/src/cats/make_sqlite3_tables.in b/bacula/src/cats/make_sqlite3_tables.in index 6f54ff397e..38ed334dff 100644 --- a/bacula/src/cats/make_sqlite3_tables.in +++ b/bacula/src/cats/make_sqlite3_tables.in @@ -73,6 +73,19 @@ CREATE TABLE Job ( CREATE INDEX inx6 ON Job (Name); +CREATE TABLE MAC ( + JobId INTEGER, + OriginalJobId INTEGER, + JobType CHAR NOT NULL, + JobLevel CHAR NOT NULL, + SchedTime DATETIME NOT NULL, + StartTime DATETIME DEFAULT 0, + EndTime DATETIME DEFAULT 0, + JobTDate BIGINT UNSIGNED DEFAULT 0, + PRIMARY KEY(JobId) + ); + + CREATE TABLE FileSet ( FileSetId INTEGER, FileSet VARCHAR(128) NOT NULL, @@ -106,6 +119,7 @@ CREATE TABLE Media ( Slot INTEGER DEFAULT 0, PoolId INTEGER UNSIGNED REFERENCES Pool NOT NULL, MediaType VARCHAR(128) NOT NULL, + MediaTypeId INTEGER UNSIGNED REFERENCES MediaType NOT NULL, LabelType TINYINT DEFAULT 0, FirstWritten DATETIME DEFAULT 0, LastWritten DATETIME DEFAULT 0, @@ -128,11 +142,13 @@ CREATE TABLE Media ( MaxVolBytes BIGINT UNSIGNED DEFAULT 0, InChanger TINYINT DEFAULT 0, StorageId INTEGER UNSIGNED REFERENCES Storage, + DeviceId INTEGER UNSIGNED REFERENCES Device, MediaAddressing TINYINT DEFAULT 0, VolReadTime BIGINT UNSIGNED DEFAULT 0, VolWriteTime BIGINT UNSIGNED DEFAULT 0, EndFile INTEGER UNSIGNED DEFAULT 0, EndBlock INTEGER UNSIGNED DEFAULT 0, + LocationId INTEGER UNSIGNED REFERENCES Location, PRIMARY KEY(MediaId) ); @@ -313,7 +329,6 @@ INSERT INTO Version (VersionId) VALUES (9); PRAGMA default_synchronous = OFF; PRAGMA default_cache_size = 10000; -PRAGMA synchronous = NORMAL; END-OF-DATA diff --git a/bacula/src/cats/make_sqlite_tables.in b/bacula/src/cats/make_sqlite_tables.in index 25afc6b7f2..38ed334dff 100644 --- a/bacula/src/cats/make_sqlite_tables.in +++ b/bacula/src/cats/make_sqlite_tables.in @@ -73,6 +73,19 @@ CREATE TABLE Job ( CREATE INDEX inx6 ON Job (Name); +CREATE TABLE MAC ( + JobId INTEGER, + OriginalJobId INTEGER, + JobType CHAR NOT NULL, + JobLevel CHAR NOT NULL, + SchedTime DATETIME NOT NULL, + StartTime DATETIME DEFAULT 0, + EndTime DATETIME DEFAULT 0, + JobTDate BIGINT UNSIGNED DEFAULT 0, + PRIMARY KEY(JobId) + ); + + CREATE TABLE FileSet ( FileSetId INTEGER, FileSet VARCHAR(128) NOT NULL, @@ -106,6 +119,7 @@ CREATE TABLE Media ( Slot INTEGER DEFAULT 0, PoolId INTEGER UNSIGNED REFERENCES Pool NOT NULL, MediaType VARCHAR(128) NOT NULL, + MediaTypeId INTEGER UNSIGNED REFERENCES MediaType NOT NULL, LabelType TINYINT DEFAULT 0, FirstWritten DATETIME DEFAULT 0, LastWritten DATETIME DEFAULT 0, @@ -128,11 +142,13 @@ CREATE TABLE Media ( MaxVolBytes BIGINT UNSIGNED DEFAULT 0, InChanger TINYINT DEFAULT 0, StorageId INTEGER UNSIGNED REFERENCES Storage, + DeviceId INTEGER UNSIGNED REFERENCES Device, MediaAddressing TINYINT DEFAULT 0, VolReadTime BIGINT UNSIGNED DEFAULT 0, VolWriteTime BIGINT UNSIGNED DEFAULT 0, EndFile INTEGER UNSIGNED DEFAULT 0, EndBlock INTEGER UNSIGNED DEFAULT 0, + LocationId INTEGER UNSIGNED REFERENCES Location, PRIMARY KEY(MediaId) ); diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 6841dffdcf..464af82d1b 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -43,7 +43,8 @@ void db_end_transaction(JCR *jcr, B_DB *mdb); /* create.c */ int db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar); -int db_create_job_record(JCR *jcr, B_DB *db, JOB_DBR *jr); +bool db_create_job_record(JCR *jcr, B_DB *db, JOB_DBR *jr); +bool db_create_mac_record(JCR *jcr, B_DB *db, MAC_DBR *mr); int db_create_media_record(JCR *jcr, B_DB *db, MEDIA_DBR *media_dbr); int db_create_client_record(JCR *jcr, B_DB *db, CLIENT_DBR *cr); bool db_create_fileset_record(JCR *jcr, B_DB *db, FILESET_DBR *fsr); @@ -67,7 +68,8 @@ bool db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, /* get.c */ bool db_get_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pdbr); int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr); -int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr); +bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr); +bool db_get_mac_record(JCR *jcr, B_DB *mdb, MAC_DBR *mr); int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **VolumeNames); int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr); int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr); diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 8f06098156..a3a877da10 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -53,16 +53,16 @@ extern void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname); /* Create a new record for the Job - * Returns: 0 on failure - * 1 on success + * Returns: false on failure + * true on success */ -int +bool db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { char dt[MAX_TIME_LENGTH]; time_t stime; struct tm tm; - int stat; + bool ok; utime_t JobTDate; char ed1[30]; @@ -86,15 +86,65 @@ db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); jr->JobId = 0; - stat = 0; + ok = false; } else { jr->JobId = sql_insert_id(mdb, N_("Job")); - stat = 1; + ok = true; } db_unlock(mdb); - return stat; + return ok; +} + +/* Create a new migration, archive, copy + * Returns: false on failure + * true on success + */ +bool +db_create_mac_record(JCR *jcr, B_DB *mdb, MAC_DBR *mr) +{ + char schedt[MAX_TIME_LENGTH], sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH]; + time_t stime; + struct tm tm; + bool ok; + utime_t JobTDate; + char ed1[30], ed2[30]; + + db_lock(mdb); + + stime = mr->SchedTime; + ASSERT(stime != 0); + + localtime_r(&stime, &tm); + strftime(schedt, sizeof(schedt), "%Y-%m-%d %T", &tm); + JobTDate = (utime_t)stime; + localtime_r(&mr->StartTime, &tm); + strftime(sdt, sizeof(sdt), "%Y-%m-%d %T", &tm); + localtime_r(&mr->EndTime, &tm); + strftime(edt, sizeof(edt), "%Y-%m-%d %T", &tm); + + /* Must create it */ + Mmsg(mdb->cmd, +"INSERT INTO MAC (OriginaJobId,JobType,JobLevel,SchedTime," +"StartTime,EndTime,JobTDate) VALUES " +"('%s','%c','%c','%s','%s','%s',%s)", + edit_int64(mr->OriginalJobId, ed1), + (char)(mr->JobType), (char)(mr->JobLevel), + schedt, sdt, edt, edit_uint64(JobTDate, ed2)); + + if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + Mmsg2(&mdb->errmsg, _("Create DB MAC record %s failed. ERR=%s\n"), + mdb->cmd, sql_strerror(mdb)); + mr->JobId = 0; + ok = false; + } else { + mr->JobId = sql_insert_id(mdb, N_("Job")); + ok = true; + } + db_unlock(mdb); + return ok; } + /* Create a JobMedia record for medium used this job * Returns: false on failure * true on success @@ -391,11 +441,11 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) /* Must create it */ Mmsg(mdb->cmd, -"INSERT INTO Media (VolumeName,MediaType,PoolId,MaxVolBytes,VolCapacityBytes," -"Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," +"INSERT INTO Media (VolumeName,MediaType,MediaTypeId,PoolId,MaxVolBytes," +"VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts," -"EndFile,EndBlock,LabelType,StorageId) " -"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s)", +"EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId) " +"VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s,0,0)", mr->VolumeName, mr->MediaType, mr->PoolId, edit_uint64(mr->MaxVolBytes,ed1), diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index c461cba6b5..f2bd3d9dd9 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -10,7 +10,7 @@ */ /* - Copyright (C) 2000-2005 Kern Sibbald + Copyright (C) 2000-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -257,10 +257,10 @@ static int db_get_path_record(JCR *jcr, B_DB *mdb) /* * Get Job record for given JobId or Job name - * Returns: 0 on failure - * 1 on success + * Returns: false on failure + * true on success */ -int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) +bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { SQL_ROW row; char ed1[50]; @@ -281,13 +281,13 @@ int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) if (!QUERY_DB(jcr, mdb, mdb->cmd)) { db_unlock(mdb); - return 0; /* failed */ + return false; /* failed */ } if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1)); sql_free_result(mdb); db_unlock(mdb); - return 0; /* failed */ + return false; /* failed */ } jr->VolSessionId = str_to_uint64(row[0]); @@ -306,10 +306,51 @@ int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) bstrncpy(jr->Name, row[13]!=NULL?row[13]:"", sizeof(jr->Name)); sql_free_result(mdb); + db_unlock(mdb); + return true; +} + +/* + * Get MAC record for given JobId + * Returns: false on failure + * true on success + */ +bool db_get_mac_record(JCR *jcr, B_DB *mdb, MAC_DBR *mr) +{ + SQL_ROW row; + char ed1[50]; + + db_lock(mdb); + Mmsg(mdb->cmd, "SELECT OriginalJobId,JobType,JobLevel," +"SchedTime,StartTime,EndTime,JobTDate" +"FROM MAC WHERE JobId=%s", + edit_int64(mr->JobId, ed1)); + + if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + db_unlock(mdb); + return 0; /* failed */ + } + if ((row = sql_fetch_row(mdb)) == NULL) { + Mmsg1(mdb->errmsg, _("No MAC record found for JobId %s\n"), ed1); + sql_free_result(mdb); + db_unlock(mdb); + return false; /* failed */ + } + + mr->OriginalJobId = str_to_int64(row[0]); + mr->JobType = (int)*row[1]; + mr->JobLevel = (int)*row[2]; + bstrncpy(mr->cSchedTime, row[3]!=NULL?row[3]:"", sizeof(mr->cSchedTime)); + bstrncpy(mr->cStartTime, row[4]!=NULL?row[4]:"", sizeof(mr->cStartTime)); + bstrncpy(mr->cEndTime, row[5]!=NULL?row[5]:"", sizeof(mr->cEndTime)); + mr->JobTDate = str_to_int64(row[6]); + sql_free_result(mdb); + db_unlock(mdb); return 1; } + /* * Find VolumeNames for a given JobId * Returns: 0 on error or no Volumes found @@ -386,7 +427,8 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS db_lock(mdb); Mmsg(mdb->cmd, "SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile," -"JobMedia.EndFile,StartBlock,JobMedia.EndBlock,Copy,Stripe" +"JobMedia.EndFile,StartBlock,JobMedia.EndBlock,Copy,Stripe," +"Slot,StorageId" " FROM JobMedia,Media WHERE JobMedia.JobId=%s" " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId", edit_int64(JobId, ed1)); @@ -394,14 +436,16 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS Dmsg1(130, "VolNam=%s\n", mdb->cmd); if (QUERY_DB(jcr, mdb, mdb->cmd)) { mdb->num_rows = sql_num_rows(mdb); - Dmsg1(130, "Num rows=%d\n", mdb->num_rows); + Dmsg1(200, "Num rows=%d\n", mdb->num_rows); if (mdb->num_rows <= 0) { Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId); stat = 0; } else { stat = mdb->num_rows; + DBId_t *SId; if (stat > 0) { *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS)); + SId = (DBId_t *)malloc(stat * sizeof(DBId_t)); } for (i=0; i < stat; i++) { if ((row = sql_fetch_row(mdb)) == NULL) { @@ -410,6 +454,7 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS stat = 0; break; } else { + DBId_t StorageId; bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH); bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH); Vols[i].FirstIndex = str_to_uint64(row[2]); @@ -420,6 +465,21 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS Vols[i].EndBlock = str_to_uint64(row[7]); // Vols[i].Copy = str_to_uint64(row[8]); // Vols[i].Stripe = str_to_uint64(row[9]); + Vols[i].Slot = str_to_uint64(row[10]); + StorageId = str_to_uint64(row[11]); + Vols[i].Storage[0] = 0; + SId[i] = StorageId; + } + } + for (i=0; i < stat; i++) { + if (SId[i] != 0) { + Mmsg(mdb->cmd, "SELECT Name from Storage WHERE StorageId=%s", + edit_int64(SId[i], ed1)); + if (QUERY_DB(jcr, mdb, mdb->cmd)) { + if ((row = sql_fetch_row(mdb)) != NULL) { + bstrncpy(Vols[i].Storage, row[0], MAX_NAME_LENGTH); + } + } } } } diff --git a/bacula/src/cats/update_mysql_tables.in b/bacula/src/cats/update_mysql_tables.in index 6fcafa766d..bb3123f4a1 100755 --- a/bacula/src/cats/update_mysql_tables.in +++ b/bacula/src/cats/update_mysql_tables.in @@ -1,9 +1,9 @@ #!/bin/sh # -# Shell script to update MySQL tables from version 1.36 to 1.38 +# Shell script to update MySQL tables from version 1.38 to 1.39 # echo " " -echo "This script will update a Bacula MySQL database from version 8 to 9" +echo "This script will update a Bacula MySQL database from version 9 to 9" echo "Depending on the size of your database," echo "this script may take several minutes to run." echo " " @@ -12,80 +12,29 @@ bindir=@SQL_BINDIR@ if $bindir/mysql $* -f <device->first()); + if (!dev) { + return false; + } + bstrncpy(device, dev->hdr.name, MAX_NAME_LENGTH); + return true; +} + /* * Our data structures were not designed completely * correctly, so the file indexes cover the full @@ -278,6 +299,7 @@ static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd) bool first = true; char *p; JobId_t JobId; + char device[MAX_NAME_LENGTH]; RBSR *bsr; if (*rx.JobIds == 0) { for (bsr=rx.bsr; bsr; bsr=bsr->next) { @@ -293,6 +315,12 @@ static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd) } fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName); fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType); + if (get_storage_device(device, bsr->VolParams[i].Storage)) { + fprintf(fd, "Device=\"%s\"\n", device); + } + if (bsr->VolParams[i].Slot > 0) { + fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot); + } fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId); fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime); if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) { @@ -346,6 +374,12 @@ static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd) } fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName); fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType); + if (get_storage_device(device, bsr->VolParams[i].Storage)) { + fprintf(fd, "Device=\"%s\"\n", device); + } + if (bsr->VolParams[i].Slot > 0) { + fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot); + } fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId); fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime); if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) { diff --git a/bacula/src/dird/mac.c b/bacula/src/dird/mac.c index aeaeca655a..d042552377 100644 --- a/bacula/src/dird/mac.c +++ b/bacula/src/dird/mac.c @@ -189,10 +189,18 @@ bool do_mac(JCR *jcr) return false; } + /* + * Target jcr is the new Job that corresponds to the original + * target job. It "runs" at the same time as the current + * migration job and becomes a new backup job that replaces + * the original backup job. Most operations on the current + * migration jcr are also done on the target jcr. + */ tjcr = jcr->target_jcr = new_jcr(sizeof(JCR), dird_free_jcr); memcpy(&tjcr->target_jr, &jcr->target_jr, sizeof(tjcr->target_jr)); - set_jcr_defaults(tjcr, tjob); + /* Turn the tjcr into a "real" job */ + set_jcr_defaults(tjcr, tjob); if (!setup_job(tjcr)) { return false; } @@ -219,6 +227,9 @@ bool do_mac(JCR *jcr) return false; } + /* Check Migration time and High/Low water marks */ + /* ***FIXME*** */ + /* If pool storage specified, use it for restore */ copy_storage(tjcr, pool->storage); diff --git a/bacula/src/dird/sql_cmds.c b/bacula/src/dird/sql_cmds.c index db289413b9..065aeba85b 100644 --- a/bacula/src/dird/sql_cmds.c +++ b/bacula/src/dird/sql_cmds.c @@ -47,6 +47,7 @@ const char *del_File = "DELETE FROM File WHERE JobId=%s"; const char *upd_Purged = "UPDATE Job Set PurgedFiles=1 WHERE JobId=%s"; const char *cnt_DelCand = "SELECT count(*) FROM DelCandidates"; const char *del_Job = "DELETE FROM Job WHERE JobId=%s"; +const char *del_MAC = "DELETE FROM MAC WHERE JobId=%s"; const char *del_JobMedia = "DELETE FROM JobMedia WHERE JobId=%s"; const char *cnt_JobMedia = "SELECT count(*) FROM JobMedia WHERE MediaId=%s"; const char *sel_JobMedia = "SELECT JobId FROM JobMedia WHERE MediaId=%s"; @@ -395,3 +396,6 @@ const char *uar_jobid_fileindex_from_dir = "GROUP BY File.FileIndex "; #endif +/* Query to get list of files from table -- presuably built by an external program */ +const char *uar_jobid_fileindex_from_table = + "SELECT JobId, FileIndex from %s"; diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 6ab82d7ff2..1edb832d95 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -1237,9 +1237,11 @@ static void do_job_delete(UAContext *ua, JobId_t JobId) Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(JobId, ed1)); db_sql_query(ua->db, query, NULL, (void *)NULL); - Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(JobId, ed1)); + Mmsg(query, "DELETE FROM MAC WHERE JobId=%s", ed1); db_sql_query(ua->db, query, NULL, (void *)NULL); - Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(JobId, ed1)); + Mmsg(query, "DELETE FROM File WHERE JobId=%s", ed1); + db_sql_query(ua->db, query, NULL, (void *)NULL); + Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", ed1); db_sql_query(ua->db, query, NULL, (void *)NULL); free_pool_memory(query); bsendmsg(ua, _("Job %s and associated records deleted from the catalog.\n"), edit_int64(JobId, ed1)); diff --git a/bacula/src/dird/ua_purge.c b/bacula/src/dird/ua_purge.c index 5a2d1189ff..5661d1db72 100644 --- a/bacula/src/dird/ua_purge.c +++ b/bacula/src/dird/ua_purge.c @@ -405,6 +405,10 @@ static int purge_jobs_from_client(UAContext *ua, CLIENT *client) db_sql_query(ua->db, query, NULL, (void *)NULL); Dmsg1(050, "Delete Job sql=%s\n", query); + Mmsg(query, "DELETE FROM MAC WHERE JobId=%s", ed1); + db_sql_query(ua->db, query, NULL, (void *)NULL); + Dmsg1(050, "Delete MAC sql=%s\n", query); + Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", ed1); db_sql_query(ua->db, query, NULL, (void *)NULL); Dmsg1(050, "Delete JobMedia sql=%s\n", query); @@ -523,6 +527,8 @@ int purge_jobs_from_volume(UAContext *ua, MEDIA_DBR *mr) db_sql_query(ua->db, query, NULL, (void *)NULL); Mmsg(query, "DELETE FROM Job WHERE JobId=%s", ed1); db_sql_query(ua->db, query, NULL, (void *)NULL); + Mmsg(query, "DELETE FROM MAC WHERE JobId=%s", ed1); + db_sql_query(ua->db, query, NULL, (void *)NULL); Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", ed1); db_sql_query(ua->db, query, NULL, (void *)NULL); Dmsg1(050, "Del sql=%s\n", query); diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 5db990706f..9fd21a4e72 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -44,6 +44,7 @@ extern char *uar_sel_all_temp1, *uar_sel_fileset, *uar_mediatype; extern char *uar_jobid_fileindex, *uar_dif, *uar_sel_all_temp; extern char *uar_count_files, *uar_jobids_fileindex; extern char *uar_jobid_fileindex_from_dir; +extern char *uar_jobid_fileindex_from_table; @@ -69,6 +70,7 @@ static void insert_one_file_or_dir(UAContext *ua, RESTORE_CTX *rx, char *date, b static int get_client_name(UAContext *ua, RESTORE_CTX *rx); static int get_date(UAContext *ua, char *date, int date_len); static int count_handler(void *ctx, int num_fields, char **row); +static bool insert_table_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *table); /* * Restore files @@ -229,6 +231,15 @@ static void free_rx(RESTORE_CTX *rx) free_name_list(&rx->name_list); } +static bool has_value(UAContext *ua, int i) +{ + if (!ua->argv[i]) { + bsendmsg(ua, _("Missing value for keyword: %s\n"), ua->argk[i]); + return false; + } + return true; +} + static int get_client_name(UAContext *ua, RESTORE_CTX *rx) { /* If no client name specified yet, get it now */ @@ -237,6 +248,9 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx) /* try command line argument */ int i = find_arg_with_value(ua, N_("client")); if (i >= 0) { + if (!has_value(ua, i)) { + return 0; + } bstrncpy(rx->ClientName, ua->argv[i], sizeof(rx->ClientName)); return 1; } @@ -249,14 +263,6 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx) return 1; } -static bool has_value(UAContext *ua, int i) -{ - if (!ua->argv[i]) { - bsendmsg(ua, _("Missing value for keyword: %s\n"), ua->argk[i]); - return false; - } - return true; -} /* * The first step in the restore process is for the user to @@ -695,6 +701,10 @@ static void insert_one_file_or_dir(UAContext *ua, RESTORE_CTX *rx, char *date, b } fclose(ffd); break; + case '?': + p++; + insert_table_into_findex_list(ua, rx, p); + break; default: if (dir) { insert_dir_into_findex_list(ua, rx, ua->cmd, date); @@ -783,6 +793,36 @@ static bool insert_dir_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *di return true; } +/* + * Get the JobId and FileIndexes of all files in the specified table + */ +static bool insert_table_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *table) +{ + char ed1[50]; + + strip_trailing_junk(table); + Mmsg(rx->query, uar_jobid_fileindex_from_table, table); + + rx->found = false; + /* Find and insert jobid and File Index */ + if (!db_sql_query(ua->db, rx->query, jobid_fileindex_handler, (void *)rx)) { + bsendmsg(ua, _("Query failed: %s. ERR=%s\n"), + rx->query, db_strerror(ua->db)); + } + if (!rx->found) { + bsendmsg(ua, _("No table found: %s\n"), table); + return true; + } + /* + * Find the MediaTypes for this JobId and add to the name_list + */ + Mmsg(rx->query, uar_mediatype, edit_int64(rx->JobId, ed1)); + if (!db_sql_query(ua->db, rx->query, unique_name_list_handler, (void *)&rx->name_list)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + return false; + } + return true; +} static void split_path_and_filename(RESTORE_CTX *rx, char *name) { diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index e094287545..ba70f04ef6 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -23,16 +23,7 @@ first_rule: all dummy: # bacula-sd -SVRSRCS = stored.c ansi_label.c \ - autochanger.c acquire.c append.c \ - askdir.c authenticate.c \ - block.c butil.c dev.c \ - device.c dircmd.c dvd.c ebcdic.c fd_cmds.c job.c \ - label.c mac.c match_bsr.c mount.c parse_bsr.c \ - pythonsd.c read.c read_record.c record.c \ - reserve.c scan.c \ - spool.c status.c stored_conf.c wait.c -SVROBJS = stored.o ansi_label.o \ +SDOBJS = stored.o ansi_label.o \ autochanger.o acquire.o append.o \ askdir.o authenticate.o \ block.o butil.o dev.o \ @@ -43,39 +34,37 @@ SVROBJS = stored.o ansi_label.o \ spool.o status.o stored_conf.o wait.o # btape -TAPESRCS = btape.c block.c butil.c dev.c device.c label.c \ - ansi_label.c dvd.c ebcdic.c \ - acquire.c mount.c record.c read_record.c \ - stored_conf.c match_bsr.c parse_bsr.c spool.c TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o \ ansi_label.o dvd.o ebcdic.o \ autochanger.o acquire.o mount.o record.o read_record.o \ + reserve.o \ stored_conf.o match_bsr.o parse_bsr.o scan.o spool.o wait.o # bls BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o \ ansi_label.o dvd.o ebcdic.o \ autochanger.o acquire.o mount.o parse_bsr.o record.o \ - read_record.o scan.o stored_conf.o spool.o wait.o + read_record.o reserve.o scan.o stored_conf.o spool.o wait.o # bextract BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \ ansi_label.o dvd.o ebcdic.o \ autochanger.o acquire.o mount.o match_bsr.o parse_bsr.o butil.o \ - pythonsd.o \ - read_record.o scan.o stored_conf.o spool.o wait.o + pythonsd.o read_record.o reserve.o \ + scan.o stored_conf.o spool.o wait.o # bscan SCNOBJS = bscan.o block.o device.o dev.o label.o \ ansi_label.o dvd.o ebcdic.o \ autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \ - butil.o read_record.o scan.o stored_conf.o spool.o wait.o + butil.o read_record.o scan.o reserve.o stored_conf.o spool.o wait.o # bcopy COPYOBJS = bcopy.o block.o device.o dev.o label.o \ ansi_label.o dvd.o ebcdic.o \ autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \ - butil.o read_record.o scan.o stored_conf.o spool.o wait.o + butil.o read_record.o reserve.o \ + scan.o stored_conf.o spool.o wait.o @@ -98,13 +87,13 @@ all: Makefile bacula-sd @STATIC_SD@ bls bextract bscan btape bcopy @echo "===== Make of stored is good ====" @echo " " -bacula-sd: $(SVROBJS) ../lib/libbac.a - $(CXX) $(WLDFLAGS) $(LDFLAGS) -L../lib -o $@ $(SVROBJS) $(FDLIBS) \ +bacula-sd: $(SDOBJS) ../lib/libbac.a + $(CXX) $(WLDFLAGS) $(LDFLAGS) -L../lib -o $@ $(SDOBJS) $(FDLIBS) \ -lbac -lm $(PYTHON_LIBS) $(DLIB) $(LIBS) $(WRAPLIBS) \ $(GETTEXT_LIBS) $(OPENSSL_LIBS) -static-bacula-sd: $(SVROBJS) ../lib/libbac.a - $(CXX) $(WLDFLAGS) $(LDFLAGS) -static -L../lib -o $@ $(SVROBJS) $(FDLIBS) \ +static-bacula-sd: $(SDOBJS) ../lib/libbac.a + $(CXX) $(WLDFLAGS) $(LDFLAGS) -static -L../lib -o $@ $(SDOBJS) $(FDLIBS) \ -lbac -lm $(PYTHON_LIBS) $(DLIB) $(LIBS) $(WRAPLIBS) \ $(GETTEXT_LIBS) $(OPENSSL_LIBS) strip $@ diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index 0d779b9855..4d32968cfc 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -23,6 +23,9 @@ #include "bacula.h" /* pull in global headers */ #include "stored.h" /* pull in Storage Deamon headers */ +/* Forward referenced functions */ +static void detach_dcr_from_dev(DCR *dcr); + /********************************************************************* * Acquire device for reading. @@ -33,11 +36,11 @@ * Returns: NULL if failed for any reason * dcr if successful */ -DCR *acquire_device_for_read(DCR *dcr) +bool acquire_device_for_read(DCR *dcr) { DEVICE *dev = dcr->dev; JCR *jcr = dcr->jcr; - bool vol_ok = false; + bool ok = false; bool tape_previously_mounted; bool tape_initially_mounted; VOL_LIST *vol; @@ -69,13 +72,68 @@ DCR *acquire_device_for_read(DCR *dcr) bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type)); dcr->VolCatInfo.Slot = vol->Slot; - Dmsg4(100, "===== Vol=%s MT=%s Slt=%d Dev-MT=%s\n", dcr->VolumeName, - dcr->media_type, vol->Slot, dev->device->media_type); - - if (strcmp(dcr->media_type, dev->device->media_type) != 0) { - Dmsg2(000, "Wrong MT have=%s want=%s\n", dev->device->media_type, - dcr->media_type); - Dmsg1(000, "New storage=%s\n", vol->storage); + + /* + * If the MediaType requested for this volume is not the + * same as the current drive, we attempt to find the same + * device that was used to write the orginal volume. If + * found, we switch to using that device. + */ + Dmsg2(100, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type); + if (dcr->media_type[0] && strcmp(dcr->media_type, dev->device->media_type) != 0) { + RCTX rctx; + DIRSTORE *store; + int stat; + memset(&rctx, 0, sizeof(RCTX)); + rctx.jcr = jcr; + jcr->reserve_msgs = New(alist(10, not_owned_by_alist)); + rctx.any_drive = true; + rctx.device_name = vol->device; + store = new DIRSTORE; + memset(store, 0, sizeof(DIRSTORE)); + store->name[0] = 0; /* No dir name */ + bstrncpy(store->media_type, vol->MediaType, sizeof(store->media_type)); + bstrncpy(store->pool_name, dcr->pool_name, sizeof(store->pool_name)); + bstrncpy(store->pool_type, dcr->pool_type, sizeof(store->pool_type)); + store->append = false; + rctx.store = store; + + /* + * Note, if search_for_device() succeeds, we get a new_dcr, + * which we do not use except for the dev info. + */ + stat = search_res_for_device(rctx); + release_msgs(jcr); /* release queued messages */ + if (stat == 1) { + DCR *new_dcr = jcr->read_dcr; + dev->unblock(); + detach_dcr_from_dev(dcr); /* release old device */ + /* Copy important info from the new dcr */ + dev = dcr->dev = new_dcr->dev; + jcr->read_dcr = dcr; + dcr->device = new_dcr->device; + dcr->max_job_spool_size = dcr->device->max_job_spool_size; + if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) { + dev->attached_dcrs->append(dcr); /* attach dcr to device */ + } + new_dcr->VolumeName[0] = 0; + free_dcr(new_dcr); + dev->block(BST_DOING_ACQUIRE); + Jmsg(jcr, M_INFO, 0, _("Media Type change. New device %s chosen.\n"), + dev->print_name()); + bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); + bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type)); + dcr->VolCatInfo.Slot = vol->Slot; + bstrncpy(dcr->pool_name, store->pool_name, sizeof(dcr->pool_name)); + bstrncpy(dcr->pool_type, store->pool_type, sizeof(dcr->pool_type)); + } else if (stat == 0) { /* device busy */ + Dmsg1(000, "Device %s is busy.\n", vol->device); + } else { + /* error */ + Jmsg1(jcr, M_FATAL, 0, _("No suitable device found to read Volume \"%s\"\n"), + vol->VolumeName); + goto get_out; + } } init_device_wait_timers(dcr); @@ -106,12 +164,12 @@ DCR *acquire_device_for_read(DCR *dcr) if (dev->open(dcr, OPEN_READ_ONLY) < 0) { if (dev->dev_errno == EIO) { /* no tape loaded */ Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed (EIO): ERR=%s\n"), - dev->print_name(), dcr->VolumeName, strerror_dev(dev)); + dev->print_name(), dcr->VolumeName, dev->bstrerror()); goto default_path; } Jmsg3(jcr, M_FATAL, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"), - dev->print_name(), dcr->VolumeName, strerror_dev(dev)); + dev->print_name(), dcr->VolumeName, dev->bstrerror()); goto get_out; } Dmsg1(100, "opened dev %s OK\n", dev->print_name()); @@ -122,7 +180,7 @@ DCR *acquire_device_for_read(DCR *dcr) vol_label_status = read_dev_volume_label(dcr); switch (vol_label_status) { case VOL_OK: - vol_ok = true; + ok = true; memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); break; /* got it */ case VOL_IO_ERROR: @@ -175,7 +233,7 @@ default_path: } /* end switch */ break; } /* end for loop */ - if (!vol_ok) { + if (!ok) { Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), dev->print_name()); goto get_out; @@ -197,10 +255,7 @@ get_out: } V(dev->mutex); dev->unblock(); - if (!vol_ok) { - dcr = NULL; - } - return dcr; + return ok; } @@ -497,16 +552,12 @@ static void remove_dcr_from_dcrs(DCR *dcr) } #endif -/* - * Free up all aspects of the given dcr -- i.e. dechain it, - * release allocated memory, zap pointers, ... - */ -void free_dcr(DCR *dcr) +static void detach_dcr_from_dev(DCR *dcr) { - JCR *jcr = dcr->jcr; DEVICE *dev = dcr->dev; if (dcr->reserved_device) { + dcr->reserved_device = false; lock_device(dev); dev->reserved_device--; Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); @@ -523,10 +574,24 @@ void free_dcr(DCR *dcr) } /* Detach this dcr only if the dev is initialized */ - if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) { - dev->attached_dcrs->remove(dcr); /* detach dcr from device */ + if (dcr->dev->fd != 0 && dcr->jcr && dcr->jcr->JobType != JT_SYSTEM) { + dcr->dev->attached_dcrs->remove(dcr); /* detach dcr from device */ // remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */ } + free_unused_volume(dcr); /* free unused vols attached to this dcr */ + pthread_cond_broadcast(&dcr->dev->wait_next_vol); + pthread_cond_broadcast(&wait_device_release); +} + +/* + * Free up all aspects of the given dcr -- i.e. dechain it, + * release allocated memory, zap pointers, ... + */ +void free_dcr(DCR *dcr) +{ + + detach_dcr_from_dev(dcr); + if (dcr->block) { free_block(dcr->block); } @@ -536,8 +601,5 @@ void free_dcr(DCR *dcr) if (dcr->jcr) { dcr->jcr->dcr = NULL; } - free_unused_volume(dcr); /* free unused vols attached to this dcr */ free(dcr); - pthread_cond_broadcast(&dev->wait_next_vol); - pthread_cond_broadcast(&wait_device_release); } diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index 89517246c8..eeae53420b 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -93,7 +93,7 @@ bool do_append_data(JCR *jcr) */ if (!write_session_label(dcr, SOS_LABEL)) { Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"), - strerror_dev(dev)); + dev->bstrerror()); set_jcr_job_status(jcr, JS_ErrorTerminated); ok = false; } @@ -203,9 +203,9 @@ bool do_append_data(JCR *jcr) rec.remainder); if (!write_block_to_device(dcr)) { Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n", - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); ok = false; break; } @@ -261,7 +261,7 @@ bool do_append_data(JCR *jcr) if (ok || dev->can_write()) { if (!write_session_label(dcr, EOS_LABEL)) { Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"), - strerror_dev(dev)); + dev->bstrerror()); set_jcr_job_status(jcr, JS_ErrorTerminated); ok = false; } @@ -272,7 +272,7 @@ bool do_append_data(JCR *jcr) /* Flush out final partial block of this session */ if (!write_block_to_device(dcr)) { Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n")); ok = false; } diff --git a/bacula/src/stored/bcopy.c b/bacula/src/stored/bcopy.c index 15766ac356..b072bd9a93 100644 --- a/bacula/src/stored/bcopy.c +++ b/bacula/src/stored/bcopy.c @@ -190,8 +190,8 @@ int main (int argc, char *argv[]) free_jcr(in_jcr); free_jcr(out_jcr); - term_dev(in_dev); - term_dev(out_dev); + in_dev->term(); + out_dev->term(); return 0; } @@ -231,16 +231,16 @@ static bool record_cb(DCR *in_dcr, DEV_RECORD *rec) rec->remainder); if (!write_block_to_device(out_jcr->dcr)) { Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n", - out_dev->print_name(), strerror_dev(out_dev)); + out_dev->print_name(), out_dev->bstrerror()); Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"), - strerror_dev(out_dev)); + out_dev->bstrerror()); } } if (!write_block_to_device(out_jcr->dcr)) { Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n", - out_dev->print_name(), strerror_dev(out_dev)); + out_dev->print_name(), out_dev->bstrerror()); Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"), - strerror_dev(out_dev)); + out_dev->bstrerror()); } break; case EOM_LABEL: @@ -261,9 +261,9 @@ static bool record_cb(DCR *in_dcr, DEV_RECORD *rec) rec->remainder); if (!write_block_to_device(out_jcr->dcr)) { Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n", - out_dev->print_name(), strerror_dev(out_dev)); + out_dev->print_name(), out_dev->bstrerror()); Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"), - strerror_dev(out_dev)); + out_dev->bstrerror()); break; } } @@ -279,9 +279,6 @@ bool dir_create_jobmedia_record(DCR *dcr) { return 1; } bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} bool dir_send_job_status(JCR *jcr) {return 1;} -VOLRES *new_volume(DCR *dcr, const char *VolumeName) { return NULL; } -bool free_volume(DEVICE *dev) { return true; } -void free_unused_volume(DCR *dcr) { } bool dir_ask_sysop_to_mount_volume(DCR *dcr) diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c index 45cef4547c..4d1cf2051d 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -246,7 +246,7 @@ static void do_extract(char *devname) release_device(dcr); free_attr(attr); free_jcr(jcr); - term_dev(dev); + dev->term(); printf(_("%u files restored.\n"), num_files); return; @@ -469,9 +469,6 @@ bool dir_create_jobmedia_record(DCR *dcr) { return 1; } bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} bool dir_send_job_status(JCR *jcr) {return 1;} -VOLRES *new_volume(DCR *dcr, const char *VolumeName) { return NULL; } -bool free_volume(DEVICE *dev) { return true; } -void free_unused_volume(DCR *dcr) { } bool dir_ask_sysop_to_mount_volume(DCR *dcr) diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index a7e7fe1cf4..d1d7b2669d 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -480,7 +480,7 @@ bool write_block_to_dev(DCR *dcr) if (weof_dev(dev, 1) != 0) { /* write eof */ Dmsg0(190, "WEOF error in max file size.\n"); Jmsg(jcr, M_FATAL, 0, _("Unable to write EOF. ERR=%s\n"), - strerror_dev(dev)); + dev->bstrerror()); terminate_writing_volume(dcr); dev->dev_errno = ENOSPC; return false; @@ -626,7 +626,7 @@ static void reread_last_block(DCR *dcr) be.strerror(dev->dev_errno)); } /* Backspace over record */ - if (ok && !bsr_dev(dev, 1)) { + if (ok && !dev->bsr(1)) { berrno be; ok = false; Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), @@ -637,7 +637,7 @@ static void reread_last_block(DCR *dcr) * rewind(), but if we do that, higher levels in cleaning up, will * most likely write the EOS record over the beginning of the * tape. The rewind *is* done later in mount.c when another - * tape is requested. Note, the clrerror_dev() call in bsr_dev() + * tape is requested. Note, the clrerror_dev() call in bsr() * calls ioctl(MTCERRSTAT), which *should* fix the problem. */ } @@ -801,7 +801,7 @@ static bool do_dvd_size_checks(DCR *dcr) if (dvd_open_next_part(dcr) < 0) { Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); dev->dev_errno = EIO; return false; } @@ -911,7 +911,7 @@ reread: (dev->part < dev->num_parts)) { if (dvd_open_next_part(dcr) < 0) { Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); dev->dev_errno = EIO; return false; } @@ -994,8 +994,8 @@ reread: /* Attempt to reposition to re-read the block */ if (dev->is_tape()) { Dmsg0(200, "BSR for reread; block too big for buffer.\n"); - if (!bsr_dev(dev, 1)) { - Jmsg(jcr, M_ERROR, 0, "%s", strerror_dev(dev)); + if (!dev->bsr(1)) { + Jmsg(jcr, M_ERROR, 0, "%s", dev->bstrerror()); block->read_len = 0; return false; } diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index ed15012579..d0e317340a 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -253,7 +253,7 @@ static void do_close(JCR *jcr) free_record(rec); free_block(block); free_jcr(jcr); - term_dev(dev); + dev->term(); } @@ -435,9 +435,6 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} bool dir_send_job_status(JCR *jcr) {return 1;} int generate_job_event(JCR *jcr, const char *event) { return 1; } -VOLRES *new_volume(DCR *dcr, const char *VolumeName) { return NULL; } -bool free_volume(DEVICE *dev) { return true; } -void free_unused_volume(DCR *dcr) { } bool dir_ask_sysop_to_mount_volume(DCR *dcr) diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index ab47d88fe9..d88a10991a 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -292,7 +292,7 @@ int main (int argc, char *argv[]) } free_jcr(bjcr); - term_dev(dev); + dev->term(); return 0; } @@ -1246,9 +1246,6 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} bool dir_send_job_status(JCR *jcr) {return 1;} int generate_job_event(JCR *jcr, const char *event) { return 1; } -VOLRES *new_volume(DCR *dcr, const char *VolumeName) { return NULL; } -bool free_volume(DEVICE *dev) { return true; } -void free_unused_volume(DCR *dcr) { } bool dir_ask_sysop_to_mount_volume(DCR *dcr) { diff --git a/bacula/src/stored/bsr.h b/bacula/src/stored/bsr.h index 9f43a84707..b7f49a623b 100644 --- a/bacula/src/stored/bsr.h +++ b/bacula/src/stored/bsr.h @@ -33,7 +33,7 @@ struct VOL_LIST { VOL_LIST *next; char VolumeName[MAX_NAME_LENGTH]; char MediaType[MAX_NAME_LENGTH]; - char storage[MAX_NAME_LENGTH]; /* ***FIXME*** use alist here */ + char device[MAX_NAME_LENGTH]; /* ***FIXME*** use alist here */ int Slot; uint32_t start_file; }; @@ -52,7 +52,7 @@ struct BSR_VOLUME { BSR_VOLUME *next; char VolumeName[MAX_NAME_LENGTH]; char MediaType[MAX_NAME_LENGTH]; - char storage[MAX_NAME_LENGTH]; /* ***FIXME*** use alist here */ + char device[MAX_NAME_LENGTH]; /* ***FIXME*** use alist here */ int32_t Slot; /* Slot */ }; diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index aca4acc047..c8979749be 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -303,7 +303,7 @@ static void terminate_btape(int stat) jcr = NULL; if (dev) { - term_dev(dev); + dev->term(); } if (debug_level > 10) @@ -363,7 +363,7 @@ static void labelcmd() if (!dev->is_open()) { if (!first_open_device(dcr)) { - Pmsg1(0, _("Device open failed. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Device open failed. ERR=%s\n"), dev->bstrerror()); } } dev->rewind(dcr); @@ -388,13 +388,13 @@ static void readlabelcmd() Pmsg0(0, _("Volume label read correctly.\n")); break; case VOL_IO_ERROR: - Pmsg1(0, _("I/O error on device: ERR=%s"), strerror_dev(dev)); + Pmsg1(0, _("I/O error on device: ERR=%s"), dev->bstrerror()); break; case VOL_NAME_ERROR: Pmsg0(0, _("Volume name error\n")); break; case VOL_CREATE_ERROR: - Pmsg1(0, _("Error creating label. ERR=%s"), strerror_dev(dev)); + Pmsg1(0, _("Error creating label. ERR=%s"), dev->bstrerror()); break; case VOL_VERSION_ERROR: Pmsg0(0, _("Volume version error.\n")); @@ -421,7 +421,7 @@ static void loadcmd() { if (!load_dev(dev)) { - Pmsg1(0, _("Bad status from load. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from load. ERR=%s\n"), dev->bstrerror()); } else Pmsg1(0, _("Loaded %s\n"), dev->print_name()); } @@ -432,7 +432,7 @@ static void loadcmd() static void rewindcmd() { if (!dev->rewind(dcr)) { - Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), dev->bstrerror()); clrerror_dev(dev, -1); } else { Pmsg1(0, _("Rewound %s\n"), dev->print_name()); @@ -462,7 +462,7 @@ static void weofcmd() } if ((stat = weof_dev(dev, num)) < 0) { - Pmsg2(0, _("Bad status from weof %d. ERR=%s\n"), stat, strerror_dev(dev)); + Pmsg2(0, _("Bad status from weof %d. ERR=%s\n"), stat, dev->bstrerror()); return; } else { if (num==1) { @@ -484,7 +484,7 @@ static void weofcmd() static void eomcmd() { if (!dev->eod()) { - Pmsg1(0, "%s", strerror_dev(dev)); + Pmsg1(0, "%s", dev->bstrerror()); return; } else { Pmsg0(0, _("Moved to end of medium.\n")); @@ -514,7 +514,7 @@ static void bsfcmd() } if (!dev->bsf(num)) { - Pmsg1(0, _("Bad status from bsf. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from bsf. ERR=%s\n"), dev->bstrerror()); } else { Pmsg2(0, _("Backspaced %d file%s.\n"), num, num==1?"":"s"); } @@ -532,8 +532,8 @@ static void bsrcmd() if (num <= 0) { num = 1; } - if (!bsr_dev(dev, num)) { - Pmsg1(0, _("Bad status from bsr. ERR=%s\n"), strerror_dev(dev)); + if (!dev->bsr(num)) { + Pmsg1(0, _("Bad status from bsr. ERR=%s\n"), dev->bstrerror()); } else { Pmsg2(0, _("Backspaced %d record%s.\n"), num, num==1?"":"s"); } @@ -700,18 +700,18 @@ static int re_read_block_test() weofcmd(); } if (!dev->bsf(1)) { - Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Backspace file failed! ERR=%s\n"), dev->bstrerror()); goto bail_out; } if (dev_cap(dev, CAP_TWOEOF)) { if (!dev->bsf(1)) { - Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Backspace file failed! ERR=%s\n"), dev->bstrerror()); goto bail_out; } } Pmsg0(0, _("Backspaced over EOF OK.\n")); - if (!bsr_dev(dev, 1)) { - Pmsg1(0, _("Backspace record failed! ERR=%s\n"), strerror_dev(dev)); + if (!dev->bsr(1)) { + Pmsg1(0, _("Backspace record failed! ERR=%s\n"), dev->bstrerror()); goto bail_out; } Pmsg0(0, _("Backspace record OK.\n")); @@ -772,7 +772,7 @@ static int write_read_test() block = dcr->block; rec = new_record(); if (!dev->rewind(dcr)) { - Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), dev->bstrerror()); goto bail_out; } rec->data = check_pool_memory_size(rec->data, block->buf_len); @@ -814,7 +814,7 @@ static int write_read_test() weofcmd(); } if (!dev->rewind(dcr)) { - Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), dev->bstrerror()); goto bail_out; } else { Pmsg0(0, _("Rewind OK.\n")); @@ -884,7 +884,7 @@ static int position_test() empty_block(block); rec = new_record(); if (!dev->rewind(dcr)) { - Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), dev->bstrerror()); goto bail_out; } rec->data = check_pool_memory_size(rec->data, block->buf_len); @@ -926,7 +926,7 @@ static int position_test() weofcmd(); } if (!dev->rewind(dcr)) { - Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), dev->bstrerror()); goto bail_out; } else { Pmsg0(0, _("Rewind OK.\n")); @@ -970,7 +970,7 @@ static int position_test() continue; } Pmsg2(-1, _("Reposition to file:block %d:%d\n"), file, blk); - if (!reposition_dev(dev, file, blk)) { + if (!dev->reposition(file, blk)) { Pmsg0(0, _("Reposition error.\n")); goto bail_out; } @@ -1194,7 +1194,7 @@ try_again: */ bmicrosleep(sleep_time, 0); if (!dev->rewind(dcr) || weof_dev(dev,1) < 0) { - Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from rewind. ERR=%s\n"), dev->bstrerror()); clrerror_dev(dev, -1); Pmsg0(-1, _("\nThe test failed, probably because you need to put\n" "a longer sleep time in the mtx-script in the load) case.\n" @@ -1206,7 +1206,7 @@ try_again: } if ((status = weof_dev(dev, 1)) < 0) { - Pmsg2(0, _("Bad status from weof %d. ERR=%s\n"), status, strerror_dev(dev)); + Pmsg2(0, _("Bad status from weof %d. ERR=%s\n"), status, dev->bstrerror()); goto bail_out; } else { Pmsg1(0, _("Wrote EOF to %s\n"), dev->print_name()); @@ -1274,7 +1274,7 @@ test_again: rewindcmd(); Pmsg0(0, _("Now forward spacing 1 file.\n")); if (!dev->fsf(1)) { - Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), dev->bstrerror()); goto bail_out; } Pmsg2(-1, _("We should be in file 1. I am at file %d. %s\n"), @@ -1286,7 +1286,7 @@ test_again: Pmsg0(0, _("Now forward spacing 2 files.\n")); if (!dev->fsf(2)) { - Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), dev->bstrerror()); goto bail_out; } Pmsg2(-1, _("We should be in file 3. I am at file %d. %s\n"), @@ -1299,7 +1299,7 @@ test_again: rewindcmd(); Pmsg0(0, _("Now forward spacing 4 files.\n")); if (!dev->fsf(4)) { - Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), dev->bstrerror()); goto bail_out; } Pmsg2(-1, _("We should be in file 4. I am at file %d. %s\n"), @@ -1317,7 +1317,7 @@ test_again: Pmsg0(-1, "\n"); Pmsg0(0, _("Now forward spacing 1 more file.\n")); if (!dev->fsf(1)) { - Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), dev->bstrerror()); } Pmsg2(-1, _("We should be in file 5. I am at file %d. %s\n"), dev->file, dev->file == 5 ? _("This is correct!") : _("This is NOT correct!!!!")); @@ -1464,7 +1464,7 @@ static void fsfcmd() num = 1; } if (!dev->fsf(num)) { - Pmsg1(0, _("Bad status from fsf. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from fsf. ERR=%s\n"), dev->bstrerror()); return; } if (num == 1) { @@ -1486,7 +1486,7 @@ static void fsrcmd() num = 1; } if (!dev->fsr(num)) { - Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(0, _("Bad status from fsr. ERR=%s\n"), dev->bstrerror()); return; } if (num == 1) { @@ -1593,7 +1593,7 @@ static void scancmd() clrerror_dev(dev, -1); Mmsg2(dev->errmsg, _("read error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); - Pmsg2(0, _("Bad status from read %d. ERR=%s\n"), stat, strerror_dev(dev)); + Pmsg2(0, _("Bad status from read %d. ERR=%s\n"), stat, dev->bstrerror()); if (blocks > 0) { if (blocks==1) { printf(_("1 block of %d bytes in file %d\n"), block_size, dev->file); @@ -1670,7 +1670,7 @@ static void scan_blocks() tot_files = dev->file; for (;;) { if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { - Dmsg1(100, "!read_block(): ERR=%s\n", strerror_dev(dev)); + Dmsg1(100, "!read_block(): ERR=%s\n", dev->bstrerror()); if (dev->state & ST_EOT) { if (blocks > 0) { if (blocks==1) { @@ -1709,7 +1709,7 @@ static void scan_blocks() printf(_("Short block read.\n")); continue; } - printf(_("Error reading block. ERR=%s\n"), strerror_dev(dev)); + printf(_("Error reading block. ERR=%s\n"), dev->bstrerror()); goto bail_out; } if (block->block_len != block_size) { @@ -1755,7 +1755,7 @@ static void statcmd() { int debug = debug_level; debug_level = 30; - Pmsg2(0, _("Device status: %u. ERR=%s\n"), status_dev(dev), strerror_dev(dev)); + Pmsg2(0, _("Device status: %u. ERR=%s\n"), status_dev(dev), dev->bstrerror()); #ifdef xxxx dump_volume_label(dev); #endif @@ -1851,7 +1851,7 @@ static void fillcmd() if (!write_session_label(dcr, SOS_LABEL)) { set_jcr_job_status(jcr, JS_ErrorTerminated); Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"), - strerror_dev(dev)); + dev->bstrerror()); ok = false; } Pmsg0(-1, _("Wrote Start of Session label.\n")); @@ -1972,7 +1972,7 @@ static void fillcmd() set_jcr_job_status(jcr, JS_ErrorTerminated); } if (!write_session_label(dcr, EOS_LABEL)) { - Pmsg1(000, _("Error writting end session label. ERR=%s\n"), strerror_dev(dev)); + Pmsg1(000, _("Error writting end session label. ERR=%s\n"), dev->bstrerror()); ok = false; } /* Write out final block of this session */ @@ -2137,13 +2137,13 @@ static void do_unfill() read_records(dcr, quickie_cb, my_mount_next_read_volume); Pmsg4(-1, _("Reposition from %u:%u to %u:%u\n"), dev->file, dev->block_num, last_file, last_block_num); - if (!reposition_dev(dev, last_file, last_block_num)) { - Pmsg1(-1, _("Reposition error. ERR=%s\n"), strerror_dev(dev)); + if (!dev->reposition(last_file, last_block_num)) { + Pmsg1(-1, _("Reposition error. ERR=%s\n"), dev->bstrerror()); goto bail_out; } Pmsg1(-1, _("Reading block %u.\n"), last_block_num); if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { - Pmsg1(-1, _("Error reading block: ERR=%s\n"), strerror_dev(dev)); + Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->bstrerror()); goto bail_out; } if (compare_blocks(last_block, block)) { @@ -2188,13 +2188,13 @@ static void do_unfill() * on the previous tape. */ Pmsg2(-1, _("Reposition from %u:%u to 0:1\n"), dev->file, dev->block_num); - if (!reposition_dev(dev, 0, 1)) { - Pmsg1(-1, _("Reposition error. ERR=%s\n"), strerror_dev(dev)); + if (!dev->reposition(0, 1)) { + Pmsg1(-1, _("Reposition error. ERR=%s\n"), dev->bstrerror()); goto bail_out; } Pmsg1(-1, _("Reading block %d.\n"), dev->block_num); if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { - Pmsg1(-1, _("Error reading block: ERR=%s\n"), strerror_dev(dev)); + Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->bstrerror()); goto bail_out; } if (compare_blocks(first_block, block)) { @@ -2204,13 +2204,13 @@ static void do_unfill() /* Now find and compare the last block */ Pmsg4(-1, _("Reposition from %u:%u to %u:%u\n"), dev->file, dev->block_num, last_file, last_block_num); - if (!reposition_dev(dev, last_file, last_block_num)) { - Pmsg1(-1, _("Reposition error. ERR=%s\n"), strerror_dev(dev)); + if (!dev->reposition(last_file, last_block_num)) { + Pmsg1(-1, _("Reposition error. ERR=%s\n"), dev->bstrerror()); goto bail_out; } Pmsg1(-1, _("Reading block %d.\n"), dev->block_num); if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { - Pmsg1(-1, _("Error reading block: ERR=%s\n"), strerror_dev(dev)); + Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->bstrerror()); goto bail_out; } if (compare_blocks(last_block, block)) { @@ -2337,7 +2337,7 @@ static int flush_block(DEV_BLOCK *block, int dump) } else { /* Full test in progress */ if (!fixup_device_block_write_error(jcr->dcr)) { - Pmsg1(000, _("Cannot fixup device error. %s\n"), strerror_dev(dev)); + Pmsg1(000, _("Cannot fixup device error. %s\n"), dev->bstrerror()); ok = false; unlock_device(dev); return 0; @@ -2765,7 +2765,3 @@ static void set_volume_name(const char *VolName, int volnum) bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); dcr->VolCatInfo.Slot = volnum; } - -VOLRES *new_volume(DCR *dcr, const char *VolumeName) { return NULL; } -bool free_volume(DEVICE *dev) { return true; } -void free_unused_volume(DCR *dcr) { } diff --git a/bacula/src/stored/butil.c b/bacula/src/stored/butil.c index f6b54c4107..44f190761f 100644 --- a/bacula/src/stored/butil.c +++ b/bacula/src/stored/butil.c @@ -93,6 +93,7 @@ JCR *setup_jcr(const char *name, char *dev_name, BSR *bsr, pm_strcpy(jcr->fileset_md5, "Dummy.fileset.md5"); init_autochangers(); + init_volume_list(); dcr = setup_to_access_device(jcr, dev_name, VolumeName, mode); if (!dcr) { diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 820bd43dd1..a00a6e25ea 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -131,7 +131,6 @@ init_dev(JCR *jcr, DEVRES *device) dev = (DEVICE *)malloc(sizeof(DEVICE)); memset(dev, 0, sizeof(DEVICE)); - dev->state = ST_MALLOC; /* Copy user supplied device parameters from Resource */ dev->dev_name = get_memory(strlen(device->device_name)+1); @@ -139,6 +138,7 @@ init_dev(JCR *jcr, DEVRES *device) dev->prt_name = get_memory(strlen(device->device_name) + strlen(device->hdr.name) + 20); /* We edit "Resource-name" (physical-name) */ Mmsg(dev->prt_name, "\"%s\" (%s)", device->hdr.name, device->device_name); + Dmsg1(400, "Allocate dev=%s\n", dev->print_name()); dev->capabilities = device->cap_bits; dev->min_block_size = device->min_block_size; dev->max_block_size = device->max_block_size; @@ -162,7 +162,9 @@ init_dev(JCR *jcr, DEVRES *device) if (dev->vol_poll_interval && dev->vol_poll_interval < 60) { dev->vol_poll_interval = 60; } + /* Link the dev and device structures together */ dev->device = device; + device->dev = dev; if (dev->is_fifo()) { dev->capabilities |= CAP_STREAM; /* set stream device */ @@ -1391,41 +1393,40 @@ bool DEVICE::fsr(int num) * Returns: false on failure * true on success */ -bool -bsr_dev(DEVICE *dev, int num) +bool DEVICE::bsr(int num) { struct mtop mt_com; int stat; - if (dev->fd < 0) { - dev->dev_errno = EBADF; - Mmsg0(dev->errmsg, _("Bad call to bsr_dev. Device not open\n")); - Emsg0(M_FATAL, 0, dev->errmsg); + if (fd < 0) { + dev_errno = EBADF; + Mmsg0(errmsg, _("Bad call to bsr_dev. Device not open\n")); + Emsg0(M_FATAL, 0, errmsg); return false; } - if (!dev->is_tape()) { + if (!is_tape()) { return false; } - if (!dev->has_cap(CAP_BSR)) { - Mmsg1(dev->errmsg, _("ioctl MTBSR not permitted on %s.\n"), dev->print_name()); + if (!has_cap(CAP_BSR)) { + Mmsg1(errmsg, _("ioctl MTBSR not permitted on %s.\n"), print_name()); return false; } Dmsg0(29, "bsr_dev\n"); - dev->block_num -= num; - dev->state &= ~(ST_EOF|ST_EOT|ST_EOF); + block_num -= num; + state &= ~(ST_EOF|ST_EOT|ST_EOF); mt_com.mt_op = MTBSR; mt_com.mt_count = num; - stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com); + stat = ioctl(fd, MTIOCTOP, (char *)&mt_com); if (stat < 0) { berrno be; - clrerror_dev(dev, MTBSR); - Mmsg2(dev->errmsg, _("ioctl MTBSR error on %s. ERR=%s.\n"), - dev->print_name(), be.strerror()); + clrerror_dev(this, MTBSR); + Mmsg2(errmsg, _("ioctl MTBSR error on %s. ERR=%s.\n"), + print_name(), be.strerror()); } - update_pos_dev(dev); + update_pos_dev(this); return stat == 0; } @@ -1434,59 +1435,58 @@ bsr_dev(DEVICE *dev, int num) * Returns: false on failure * true on success */ -bool -reposition_dev(DEVICE *dev, uint32_t file, uint32_t block) +bool DEVICE::reposition(uint32_t rfile, uint32_t rblock) { - if (dev->fd < 0) { - dev->dev_errno = EBADF; - Mmsg0(dev->errmsg, _("Bad call to reposition_dev. Device not open\n")); - Emsg0(M_FATAL, 0, dev->errmsg); + if (fd < 0) { + dev_errno = EBADF; + Mmsg0(errmsg, _("Bad call to reposition. Device not open\n")); + Emsg0(M_FATAL, 0, errmsg); return false; } - if (!dev->is_tape()) { - off_t pos = (((off_t)file)<<32) + (off_t)block; + if (!is_tape()) { + off_t pos = (((off_t)rfile)<<32) + (off_t)rblock; Dmsg1(100, "===== lseek_dev to %d\n", (int)pos); - if (lseek_dev(dev, pos, SEEK_SET) == (off_t)-1) { + if (lseek_dev(this, pos, SEEK_SET) == (off_t)-1) { berrno be; - dev->dev_errno = errno; - Mmsg2(dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"), - dev->print_name(), be.strerror()); + dev_errno = errno; + Mmsg2(errmsg, _("lseek_dev error on %s. ERR=%s.\n"), + print_name(), be.strerror()); return false; } - dev->file = file; - dev->block_num = block; - dev->file_addr = pos; + file = rfile; + block_num = rblock; + file_addr = pos; return true; } - Dmsg4(100, "reposition_dev from %u:%u to %u:%u\n", - dev->file, dev->block_num, file, block); - if (file < dev->file) { + Dmsg4(100, "reposition from %u:%u to %u:%u\n", + file, block_num, rfile, rblock); + if (rfile < file) { Dmsg0(100, "Rewind\n"); - if (!dev->rewind(NULL)) { + if (!rewind(NULL)) { return false; } } - if (file > dev->file) { - Dmsg1(100, "fsf %d\n", file-dev->file); - if (!dev->fsf(file-dev->file)) { - Dmsg1(100, "fsf failed! ERR=%s\n", strerror_dev(dev)); + if (rfile > file) { + Dmsg1(100, "fsf %d\n", rfile-file); + if (!fsf(rfile-file)) { + Dmsg1(100, "fsf failed! ERR=%s\n", bstrerror()); return false; } - Dmsg2(100, "wanted_file=%d at_file=%d\n", file, dev->file); + Dmsg2(100, "wanted_file=%d at_file=%d\n", rfile, file); } - if (block < dev->block_num) { - Dmsg2(100, "wanted_blk=%d at_blk=%d\n", block, dev->block_num); + if (rblock < block_num) { + Dmsg2(100, "wanted_blk=%d at_blk=%d\n", rblock, block_num); Dmsg0(100, "bsf 1\n"); - dev->bsf(1); + bsf(1); Dmsg0(100, "fsf_dev 1\n"); - dev->fsf(1); - Dmsg2(100, "wanted_blk=%d at_blk=%d\n", block, dev->block_num); + fsf(1); + Dmsg2(100, "wanted_blk=%d at_blk=%d\n", rblock, block_num); } - if (dev->has_cap(CAP_POSITIONBLOCKS) && block > dev->block_num) { + if (has_cap(CAP_POSITIONBLOCKS) && rblock > block_num) { /* Ignore errors as Bacula can read to the correct block */ - Dmsg1(100, "fsr %d\n", block-dev->block_num); - return dev->fsr(block-dev->block_num); + Dmsg1(100, "fsr %d\n", rblock-block_num); + return fsr(rblock-block_num); } return true; } @@ -1541,18 +1541,6 @@ weof_dev(DEVICE *dev, int num) return stat; } -/* - * Return string message with last error in English - * Be careful not to call this routine from within dev.c - * while editing an Mmsg() or you will end up in a recursive - * loop creating a Segmentation Violation. - */ -char * -strerror_dev(DEVICE *dev) -{ - return dev->errmsg; -} - /* * If implemented in system, clear the tape @@ -1672,15 +1660,6 @@ clrerror_dev(DEVICE *dev, int func) #endif } -/* - * Flush buffer contents - * No longer used. - */ -int flush_dev(DEVICE *dev) -{ - return 1; -} - /* * Close the device */ @@ -1999,41 +1978,35 @@ uint32_t dev_file(DEVICE *dev) /* * Free memory allocated for the device */ -void -term_dev(DEVICE *dev) +void DEVICE::term(void) { - if (!dev) { - dev->dev_errno = EBADF; - Mmsg0(dev->errmsg, _("Bad call to term_dev. Device not open\n")); - Emsg0(M_FATAL, 0, dev->errmsg); - return; - } - Dmsg1(29, "term_dev: %s\n", dev->print_name()); - dev->close(); - if (dev->dev_name) { - free_memory(dev->dev_name); - dev->dev_name = NULL; - } - if (dev->prt_name) { - free_memory(dev->prt_name); - dev->prt_name = NULL; - } - if (dev->errmsg) { - free_pool_memory(dev->errmsg); - dev->errmsg = NULL; - } - pthread_mutex_destroy(&dev->mutex); - pthread_cond_destroy(&dev->wait); - pthread_cond_destroy(&dev->wait_next_vol); - pthread_mutex_destroy(&dev->spool_mutex); - rwl_destroy(&dev->lock); - if (dev->attached_dcrs) { - delete dev->attached_dcrs; - dev->attached_dcrs = NULL; - } - if (dev->state & ST_MALLOC) { - free((char *)dev); - } + Dmsg1(900, "term dev: %s\n", print_name()); + close(); + if (dev_name) { + free_memory(dev_name); + dev_name = NULL; + } + if (prt_name) { + free_memory(prt_name); + prt_name = NULL; + } + if (errmsg) { + free_pool_memory(errmsg); + errmsg = NULL; + } + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&wait); + pthread_cond_destroy(&wait_next_vol); + pthread_mutex_destroy(&spool_mutex); + rwl_destroy(&lock); + if (attached_dcrs) { + delete attached_dcrs; + attached_dcrs = NULL; + } + if (device) { + device->dev = NULL; + } + free((char *)this); } /* diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 76e8cdfb48..72a9607044 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -339,13 +339,15 @@ public: void clear_mounted() { state &= ~ST_MOUNTED; }; void clear_media() { state &= ~ST_MEDIA; }; void clear_short_block() { state &= ~ST_SHORT; }; - void clear_freespace_ok() { state &= ~ST_FREESPACE_OK; } + void clear_freespace_ok() { state &= ~ST_FREESPACE_OK; }; + char *bstrerror(void) { return errmsg; }; void block(int why); /* in dev.c */ void unblock(); /* in dev.c */ void close(); /* in dev.c */ bool truncate(DCR *dcr); /* in dev.c */ int open(DCR *dcr, int mode); /* in dev.c */ + void term(void); /* in dev.c */ bool rewind(DCR *dcr); /* in dev.c */ bool mount(int timeout); /* in dev.c */ bool unmount(int timeout); /* in dev.c */ @@ -356,7 +358,9 @@ public: bool eod(); /* in dev.c */ bool fsr(int num); /* in dev.c */ bool fsf(int num); /* in dev.c */ + bool bsr(int num); /* in dev.c */ bool scan_dir_for_volume(DCR *dcr); /* in scan.c */ + bool reposition(uint32_t rfile, uint32_t rblock); /* in dev.c */ void set_blocked(int block) { dev_blocked = block; }; int get_blocked() const { return dev_blocked; }; diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index a5b3dae44e..30f6c403f6 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -293,9 +293,9 @@ bool open_device(DCR *dcr) * (when there is no DVD, or when the one inserted is a wrong one) */ if (!dev->poll && !dev->is_dvd() && !dev->is_removable()) { Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); Pmsg2(000, _("Unable to open archive %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); } return false; } diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 5c6817972a..a371688fe3 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -441,7 +441,7 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, case VOL_IO_ERROR: case VOL_NO_LABEL: if (!write_new_volume_label_to_dev(dcr, newname, poolname)) { - bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev)); + bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror()); break; } bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName)); @@ -450,7 +450,7 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, newname, dev->print_name()); break; case VOL_NO_MEDIA: - bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev)); + bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror()); break; default: bnet_fsend(dir, _("3913 Cannot label Volume. " @@ -606,7 +606,7 @@ static bool mount_cmd(JCR *jcr) /* We freed the device, so reopen it and wake any waiting threads */ if (dev->open(dcr, OPEN_READ_ONLY) < 0) { bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), - strerror_dev(dev)); + dev->bstrerror()); if (dev->dev_blocked == BST_UNMOUNTED) { /* We blocked the device, so unblock it */ Dmsg0(100, "Unmounted. Unblocking device\n"); @@ -659,7 +659,7 @@ static bool mount_cmd(JCR *jcr) } else if (dev->is_tape()) { if (dev->open(dcr, OPEN_READ_ONLY) < 0) { bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), - strerror_dev(dev)); + dev->bstrerror()); break; } read_label(dcr); @@ -676,7 +676,7 @@ static bool mount_cmd(JCR *jcr) bnet_fsend(dir, _("3002 Device %s is mounted.\n"), dev->print_name()); } else { - bnet_fsend(dir, _("3907 %s"), strerror_dev(dev)); + bnet_fsend(dir, _("3907 %s"), dev->bstrerror()); } } else { /* must be file */ bnet_fsend(dir, _("3906 File device %s is always mounted.\n"), diff --git a/bacula/src/stored/dvd.c b/bacula/src/stored/dvd.c index fd411fffaf..8284256911 100644 --- a/bacula/src/stored/dvd.c +++ b/bacula/src/stored/dvd.c @@ -703,7 +703,7 @@ bool dvd_close_job(DCR *dcr) update the part number. */ if (ok && (dvd_open_next_part(dcr) < 0)) { Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); dev->dev_errno = EIO; ok = false; } diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index 72340278f8..612c2b4b97 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -102,7 +102,7 @@ int read_dev_volume_label(DCR *dcr) if (!dev->rewind(dcr)) { Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg); return VOL_NO_MEDIA; } @@ -141,14 +141,14 @@ int read_dev_volume_label(DCR *dcr) if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula " "labeled Volume, because: ERR=%s"), NPRT(VolName), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); Dmsg1(30, "%s", jcr->errmsg); } else if (!read_record_from_block(block, record)) { Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n")); Dmsg1(30, "%s", jcr->errmsg); } else if (!unser_volume_label(dev, record)) { Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"), - strerror_dev(dev)); + dev->bstrerror()); Dmsg1(30, "%s", jcr->errmsg); } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 && strcmp(dev->VolHdr.Id, OldBaculaId) != 0) { @@ -309,7 +309,7 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *Po if (!dev->rewind(dcr)) { free_volume(dev); memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); - Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev)); + Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->bstrerror()); if (!forge_on) { goto bail_out; } @@ -338,7 +338,7 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *Po /* Temporarily mark in append state to enable writing */ dev->set_append(); if (!write_record_to_block(dcr->block, dcr->rec)) { - Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev)); + Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror()); goto bail_out; } else { Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name()); @@ -346,7 +346,7 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *Po Dmsg0(99, "Call write_block_to_dev()\n"); if (!write_block_to_dev(dcr)) { - Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev)); + Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror()); goto bail_out; } Dmsg0(99, " Wrote block to device\n"); @@ -401,12 +401,12 @@ bool rewrite_volume_label(DCR *dcr, bool recycle) if (!dev_cap(dev, CAP_STREAM)) { if (!dev->rewind(dcr)) { Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); } if (recycle) { if (!dev->truncate(dcr)) { Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); } } @@ -428,7 +428,7 @@ bool rewrite_volume_label(DCR *dcr, bool recycle) Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd); if (!write_block_to_dev(dcr)) { Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); Dmsg0(200, "===ERROR write block to dev\n"); return false; } diff --git a/bacula/src/stored/mac.c b/bacula/src/stored/mac.c index 5e51f453f6..aedbf100b4 100644 --- a/bacula/src/stored/mac.c +++ b/bacula/src/stored/mac.c @@ -96,7 +96,7 @@ bail_out: /* Flush out final partial block of this session */ if (!write_block_to_device(jcr->dcr)) { Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n")); ok = false; } @@ -172,9 +172,9 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) if (!write_block_to_device(jcr->dcr)) { DEVICE *dev = jcr->dcr->dev; Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n", - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); return false; } } diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index 9387bc3612..8b86db484b 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -335,7 +335,7 @@ read_volume: dcr->VolumeName); if (!dev->eod()) { Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), dev->bstrerror()); mark_volume_in_error(dcr); goto mount_next_vol; } diff --git a/bacula/src/stored/parse_bsr.c b/bacula/src/stored/parse_bsr.c index c6eec08a18..1bd1fa37ba 100755 --- a/bacula/src/stored/parse_bsr.c +++ b/bacula/src/stored/parse_bsr.c @@ -29,7 +29,7 @@ typedef BSR * (ITEM_HANDLER)(LEX *lc, BSR *bsr); static BSR *store_vol(LEX *lc, BSR *bsr); static BSR *store_mediatype(LEX *lc, BSR *bsr); -static BSR *store_storage(LEX *lc, BSR *bsr); +static BSR *store_device(LEX *lc, BSR *bsr); static BSR *store_client(LEX *lc, BSR *bsr); static BSR *store_job(LEX *lc, BSR *bsr); static BSR *store_jobid(LEX *lc, BSR *bsr); @@ -72,9 +72,9 @@ struct kw_items items[] = { {"exclude", store_exclude}, {"volfile", store_volfile}, {"volblock", store_volblock}, - {"stream", store_stream}, - {"slot", store_slot}, - {"storage", store_storage}, + {"stream", store_stream}, + {"slot", store_slot}, + {"device", store_device}, {NULL, NULL} }; @@ -270,8 +270,8 @@ static BSR *store_mediatype(LEX *lc, BSR *bsr) return bsr; } -/* Shove the Storage name in each Volume in the current bsr */ -static BSR *store_storage(LEX *lc, BSR *bsr) +/* Shove the Device name in each Volume in the current bsr */ +static BSR *store_device(LEX *lc, BSR *bsr) { int token; @@ -280,13 +280,13 @@ static BSR *store_storage(LEX *lc, BSR *bsr) return NULL; } if (!bsr->volume) { - Emsg1(M_ERROR,0, _("Storage %s in bsr at inappropriate place.\n"), + Emsg1(M_ERROR,0, _("Device \"%s\" in bsr at inappropriate place.\n"), lc->str); return bsr; } BSR_VOLUME *bv; for (bv=bsr->volume; bv; bv=bv->next) { - bstrncpy(bv->storage, lc->str, sizeof(bv->storage)); + bstrncpy(bv->device, lc->str, sizeof(bv->device)); } return bsr; } @@ -707,7 +707,7 @@ void dump_volume(BSR_VOLUME *volume) if (volume) { Pmsg1(-1, _("VolumeName : %s\n"), volume->VolumeName); Pmsg1(-1, _(" MediaType : %s\n"), volume->MediaType); - Pmsg1(-1, _(" Storage : %s\n"), volume->storage); + Pmsg1(-1, _(" Device : %s\n"), volume->device); Pmsg1(-1, _(" Slot : %d\n"), volume->Slot); dump_volume(volume->next); } @@ -904,7 +904,7 @@ void create_restore_volume_list(JCR *jcr) vol = new_restore_volume(); bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName)); bstrncpy(vol->MediaType, bsrvol->MediaType, sizeof(vol->MediaType)); - bstrncpy(vol->storage, bsrvol->storage, sizeof(vol->storage)); + bstrncpy(vol->device, bsrvol->device, sizeof(vol->device)); vol->Slot = bsrvol->Slot; vol->start_file = sfile; if (add_restore_volume(jcr, vol)) { diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 9c8d3b4791..7b7da1390e 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -23,7 +23,7 @@ uint32_t new_VolSessionId(); /* From acquire.c */ DCR *acquire_device_for_append(DCR *dcr); -DCR *acquire_device_for_read(DCR *dcr); +bool acquire_device_for_read(DCR *dcr); bool release_device(DCR *dcr); DCR *new_dcr(JCR *jcr, DEVICE *dev); void free_dcr(DCR *dcr); @@ -98,11 +98,9 @@ uint32_t status_dev(DEVICE *dev); bool eod_dev(DEVICE *dev); bool fsf_dev(DEVICE *dev, int num); bool bsf_dev(DEVICE *dev, int num); -bool 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); -bool reposition_dev(DEVICE *dev, uint32_t file, uint32_t block); void init_device_wait_timers(DCR *dcr); void init_jcr_device_wait_timers(JCR *jcr); bool double_dev_wait_time(DEVICE *dev); @@ -221,6 +219,8 @@ void list_volumes(BSOCK *user); bool is_volume_in_use(DCR *dcr); void send_drive_reserve_messages(JCR *jcr, BSOCK *user); bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx); +int search_res_for_device(RCTX &rctx); +void release_msgs(JCR *jcr); /* From spool.c */ diff --git a/bacula/src/stored/read.c b/bacula/src/stored/read.c index 633cea29fa..412b4a20b7 100644 --- a/bacula/src/stored/read.c +++ b/bacula/src/stored/read.c @@ -75,7 +75,7 @@ bool do_read_data(JCR *jcr) /* Send end of data to FD */ bnet_sig(fd, BNET_EOD); - if (!release_device(dcr)) { + if (!release_device(jcr->read_dcr)) { ok = false; } diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c index c6e77c0f1a..f450574132 100644 --- a/bacula/src/stored/read_record.c +++ b/bacula/src/stored/read_record.c @@ -86,6 +86,11 @@ bool read_records(DCR *dcr, break; } jcr->mount_next_volume = false; + /* + * The Device can change at the end of a tape, so refresh it + * from the dcr. + */ + dev = dcr->dev; /* * We just have a new tape up, now read the label (first record) * and pass it off to the callback routine, then continue @@ -280,7 +285,7 @@ static bool try_repositioning(JCR *jcr, DEV_RECORD *rec, DEVICE *dev) Dmsg4(300, "Try_Reposition from (file:block) %u:%u to %u:%u\n", dev->file, dev->block_num, bsr->volfile->sfile, bsr->volblock->sblock); - reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock); + dev->reposition(bsr->volfile->sfile, bsr->volblock->sblock); rec->Block = 0; } return false; @@ -304,7 +309,7 @@ static BSR *position_to_first_file(JCR *jcr, DEVICE *dev) bsr->volfile->sfile, bsr->volblock->sblock); Dmsg2(300, "Forward spacing to file:block %u:%u.\n", bsr->volfile->sfile, bsr->volblock->sblock); - reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock); + dev->reposition(bsr->volfile->sfile, bsr->volblock->sblock); } } return bsr; diff --git a/bacula/src/stored/reserve.c b/bacula/src/stored/reserve.c index 362eccac70..dd38158e44 100644 --- a/bacula/src/stored/reserve.c +++ b/bacula/src/stored/reserve.c @@ -33,13 +33,11 @@ static pthread_mutex_t search_lock = PTHREAD_MUTEX_INITIALIZER; /* Forward referenced functions */ static int can_reserve_drive(DCR *dcr, RCTX &rctx); -static int search_res_for_device(RCTX &rctx); static int reserve_device(RCTX &rctx); static bool reserve_device_for_read(DCR *dcr); static bool reserve_device_for_append(DCR *dcr, RCTX &rctx); static bool use_storage_cmd(JCR *jcr); static void queue_reserve_message(JCR *jcr); -static void release_msgs(JCR *jcr); /* Requests from the Director daemon */ static char use_storage[] = "use storage=%127s media_type=%127s " @@ -180,6 +178,7 @@ bail_out: void free_unused_volume(DCR *dcr) { VOLRES *vol; + P(vol_list_lock); for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) { if (vol->dcr == dcr && (vol->dev == NULL || @@ -342,6 +341,7 @@ static bool use_storage_cmd(JCR *jcr) */ if (ok) { bool first = true; /* print wait message once */ + rctx.notify_dir = true; for ( ; !job_canceled(jcr); ) { P(search_lock); /* only one thread at a time */ while ((msg = (char *)msgs->pop())) { @@ -450,11 +450,14 @@ all_done: return ok; } -static void release_msgs(JCR *jcr) +void release_msgs(JCR *jcr) { alist *msgs = jcr->reserve_msgs; char *msg; + if (!msgs) { + return; + } P(search_lock); while ((msg = (char *)msgs->pop())) { free(msg); @@ -510,7 +513,7 @@ bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx) * Search for a particular storage device with particular storage * characteristics (MediaType). */ -static int search_res_for_device(RCTX &rctx) +int search_res_for_device(RCTX &rctx) { AUTOCHANGER *changer; BSOCK *dir = rctx.jcr->dir_bsock; @@ -538,10 +541,14 @@ static int search_res_for_device(RCTX &rctx) Dmsg2(100, "Device %s reserved=%d for read.\n", rctx.device->hdr.name, rctx.jcr->read_dcr->dev->reserved_device); } - pm_strcpy(dev_name, rctx.device->hdr.name); - bash_spaces(dev_name); - ok = bnet_fsend(dir, OK_device, dev_name.c_str()); /* Return real device name */ - Dmsg1(100, ">dird changer: %s", dir->msg); + if (rctx.notify_dir) { + pm_strcpy(dev_name, rctx.device->hdr.name); + bash_spaces(dev_name); + ok = bnet_fsend(dir, OK_device, dev_name.c_str()); /* Return real device name */ + Dmsg1(100, ">dird changer: %s", dir->msg); + } else { + ok = true; + } return ok ? 1 : -1; } } @@ -557,10 +564,13 @@ static int search_res_for_device(RCTX &rctx) if (stat != 1) { return stat; } - Dmsg1(220, "Got: %s", dir->msg); - bash_spaces(rctx.device_name); - ok = bnet_fsend(dir, OK_device, rctx.device_name); - Dmsg1(100, ">dird dev: %s", dir->msg); + if (rctx.notify_dir) { + bash_spaces(rctx.device_name); + ok = bnet_fsend(dir, OK_device, rctx.device_name); + Dmsg1(100, ">dird dev: %s", dir->msg); + } else { + ok = true; + } return ok ? 1 : -1; } } diff --git a/bacula/src/stored/reserve.h b/bacula/src/stored/reserve.h index 78e35c897b..38e77dbdc8 100644 --- a/bacula/src/stored/reserve.h +++ b/bacula/src/stored/reserve.h @@ -56,5 +56,6 @@ public: bool have_volume; /* Have DIR suggested vol name */ bool suitable_device; /* at least one device is suitable */ bool autochanger_only; /* look at autochangers only */ + bool notify_dir; /* Notify DIR about device */ char VolumeName[MAX_NAME_LENGTH]; /* Vol name suggested by DIR */ }; diff --git a/bacula/src/stored/spool.c b/bacula/src/stored/spool.c index cd73dea27b..9cf930447b 100644 --- a/bacula/src/stored/spool.c +++ b/bacula/src/stored/spool.c @@ -246,7 +246,7 @@ static bool despool_data(DCR *dcr, bool commit) ok = write_block_to_device(dcr); if (!ok) { Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), - dcr->dev->print_name(), strerror_dev(dcr->dev)); + dcr->dev->print_name(), dcr->dev->bstrerror()); } Dmsg3(800, "Write block ok=%d FI=%d LI=%d\n", ok, block->FirstIndex, block->LastIndex); } diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index 095a9ab2f4..71d180a6bf 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -449,7 +449,7 @@ void *device_initialization(void *arg) foreach_res(device, R_DEVICE) { Dmsg1(90, "calling init_dev %s\n", device->device_name); - device->dev = dev = init_dev(NULL, device); + dev = init_dev(NULL, device); Dmsg1(10, "SD init done %s\n", device->device_name); if (!dev) { Jmsg1(NULL, M_ERROR, 0, _("Could not initialize %s\n"), device->device_name); @@ -548,7 +548,8 @@ void terminate_stored(int sig) Dmsg1(10, "Term device %s\n", device->device_name); if (device->dev) { free_volume(device->dev); - term_dev(device->dev); + device->dev->term(); + device->dev = NULL; } else { Dmsg1(10, "No dev structure %s\n", device->device_name); } diff --git a/bacula/src/version.h b/bacula/src/version.h index 1b91bd96f7..0870424a32 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "1.39.5" -#define BDATE "14 February 2006" -#define LSMDATE "14Feb06" +#define BDATE "20 February 2006" +#define LSMDATE "20Feb06" /* Debug flags */ #undef DEBUG -- 2.39.5