From e8c6cfbc0b69fc3ca6f4e89e72c1c18a785040a8 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sun, 30 Jul 2006 16:00:35 +0000 Subject: [PATCH] kes Make bscan ignore ACL streams. kes Update projects files with new Feature Requests. kes Generate current English and French manuals and upload them to the site. kes Update the home page to include the new British/French flags to switch between translations. Work done by Alexandre Baron. kes Make disk-changer script print an error message if the changer directory is not defined. kes Create a generic DB routine for getting an int (32/64 bit) from the DB. kes Add more migration code. kes Add a few more files to .cvsignore here and there. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@3201 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/kernstodo | 5 +- bacula/kes-1.39 | 26 +++ bacula/projects | 118 ++++++++++++- bacula/scripts/disk-changer.in | 5 + bacula/src/cats/bdb.c | 4 + bacula/src/cats/cats.h | 9 +- bacula/src/cats/protos.h | 1 + bacula/src/cats/sql.c | 22 ++- bacula/src/dird/catreq.c | 8 +- bacula/src/dird/dird_conf.h | 4 +- bacula/src/dird/migrate.c | 229 ++++++++++++++++--------- bacula/src/filed/job.c | 4 +- bacula/src/jcr.h | 2 +- bacula/src/stored/bscan.c | 6 + bacula/src/version.h | 6 +- bacula/src/win32/.cvsignore | 4 + bacula/src/win32/pebuilder/.cvsignore | 1 + bacula/src/win32/wx-console/.cvsignore | 1 + 18 files changed, 350 insertions(+), 105 deletions(-) diff --git a/bacula/kernstodo b/bacula/kernstodo index a61bfa79aa..4926a8fdb7 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 16 July 2006 + 30 July 2006 Major development: Project Developer @@ -28,6 +28,9 @@ Document: Priority: For 1.39: +- Fix bextract to restore ACLs, or better yet, use common + routines. +- Do we migrate appendable Volumes? - Remove queue.c code. - Add bconsole option to use stdin/out instead of conio. - Fix ClientRunBefore/AfterJob compatibility. diff --git a/bacula/kes-1.39 b/bacula/kes-1.39 index ab161b5e51..995e59bf28 100644 --- a/bacula/kes-1.39 +++ b/bacula/kes-1.39 @@ -2,6 +2,32 @@ Kern Sibbald General: +30Jul06 +kes Make bscan ignore ACL streams. +kes Update projects files with new Feature Requests. +kes Generate current English and French manuals and upload + them to the site. +kes Update the home page to include the new British/French flags to + switch between translations. Work done by Alexandre Baron. +kes Make disk-changer script print an error message if the changer + directory is not defined. +kes Create a generic DB routine for getting an int (32/64 bit) from + the DB. +kes Add more migration code. +kes Add a few more files to .cvsignore here and there. + +Version 1.39.18 +29Jul06 +- Incremented the version number to signify that all of Robert's code + for Win32 that was in the branch is now integrated into the HEAD, + and that Eric has submitted code that we hope will provide limited + backward compatibility with 1.38 file daemons (more testing to be + done). +- I rationalized a few of the names of the variables (mainly jcr names) + that are used during migration as keeping three different jcrs at the + same time clear in one's head is not easy. + +Version 1.39.17 28Jul06 - Tweak new runscript feature to work with 1.38.x FDs. - Correct crypto.c to fix segfault when restoring an encrypted stream diff --git a/bacula/projects b/bacula/projects index 3bc11156a6..6e126ec186 100644 --- a/bacula/projects +++ b/bacula/projects @@ -1,8 +1,8 @@ Projects: Bacula Projects Roadmap - 07 December 2005 - (prioritized by user vote) + Prioritized by user vote 07 December 2005 + Status updated 30 July 2006 Summary: Item 1: Implement data encryption (as opposed to comm encryption) @@ -37,7 +37,7 @@ Below, you will find more information on future projects: Item 1: Implement data encryption (as opposed to comm encryption) Date: 28 October 2005 Origin: Sponsored by Landon and 13 contributors to EFF. - Status: Landon Fuller has implemented this in 1.39.x. + Status: Done: Landon Fuller has implemented this in 1.39.x. What: Currently the data that is stored on the Volume is not encrypted. For confidentiality, encryption of data at @@ -51,7 +51,7 @@ Item 2: Implement Migration that moves Jobs from one Pool to another. Origin: Sponsored by Riege Software International GmbH. Contact: Daniel Holtkamp Date: 28 October 2005 - Status: Partially working in 1.39, more to do. Assigned to + Status: 90% complete: Working in 1.39, more to do. Assigned to Kern. What: The ability to copy, move, or archive data that is on a @@ -389,7 +389,8 @@ Item 9: Implement new {Client}Run{Before|After}Job feature. Item 10: Merge multiple backups (Synthetic Backup or Consolidation). Origin: Marc Cousin and Eric Bollengier Date: 15 November 2005 - Status: Depends on first implementing project Item 1 (Migration). + Status: Waiting implementation. Depends on first implementing + project Item 2 (Migration). What: A merged backup is a backup made without connecting to the Client. It would be a Merge of existing backups into a single backup. @@ -446,7 +447,7 @@ Item 12: Directive/mode to backup only file changes, not entire file Date: 11 November 2005 Origin: Joshua Kugler Marek Bajon - Status: RFC + Status: What: Currently when a file changes, the entire file will be backed up in the next incremental or full backup. To save space on the tapes @@ -755,6 +756,7 @@ Item n: One line summary ... =============================================== Feature requests submitted after cutoff for December 2005 vote + and not yet discussed. =============================================== Item n: Allow skipping execution of Jobs Date: 29 November 2005 @@ -798,4 +800,106 @@ Item n: archive data could do this bit ability to save data uncompresed so it can be read in any other system (future proof data) save the catalog with the disk as some kind of menu - system + system + +Item : Tray monitor window cleanups + Origin: Alan Brown ajb2 at mssl dot ucl dot ac dot uk + Date: 24 July 2006 + Status: + What: Resizeable and scrollable windows in the tray monitor. + + Why: With multiple clients, or with many jobs running, the displayed + window often ends up larger than the available screen, making + the trailing items difficult to read. + + Notes: + + Item : Clustered file-daemons + Origin: Alan Brown ajb2 at mssl dot ucl dot ac dot uk + Date: 24 July 2006 + Status: + What: A "virtual" filedaemon, which is actually a cluster of real ones. + + Why: In the case of clustered filesystems (SAN setups, GFS, or OCFS2, etc) + multiple machines may have access to the same set of filesystems + + For performance reasons, one may wish to initate backups from + several of these machines simultaneously, instead of just using + one backup source for the common clustered filesystem. + + For obvious reasons, normally backups of $A-FD/$PATH and + B-FD/$PATH are treated as different backup sets. In this case + they are the same communal set. + + Likewise when restoring, it would be easier to just specify + one of the cluster machines and let bacula decide which to use. + + This can be faked to some extent using DNS round robin entries + and a virtual IP address, however it means "status client" will + always give bogus answers. Additionally there is no way of + spreading the load evenly among the servers. + + What is required is something similar to the storage daemon + autochanger directives, so that Bacula can keep track of + operating backups/restores and direct new jobs to a "free" + client. + + Notes: + +Item : Tray monitor window cleanups + Origin: Alan Brown ajb2 at mssl dot ucl dot ac dot uk + Date: 24 July 2006 + Status: + What: Resizeable and scrollable windows in the tray monitor. + + Why: With multiple clients, or with many jobs running, the displayed + window often ends up larger than the available screen, making + the trailing items difficult to read. + + Notes: + +Item: Commercial database support + Origin: Russell Howe + Date: 26 July 2006 + Status: + + What: It would be nice for the database backend to support more + databases. I'm thinking of SQL Server at the moment, but I guess Oracle, + DB2, MaxDB, etc are all candidates. SQL Server would presumably be + implemented using FreeTDS or maybe an ODBC library? + + Why: We only really have one database server, which is MS SQL Server + 2000. Maintaining a second one for the backup software (we grew out of + SQLite, which I liked, but which didn't work so well with our database + size). We don't really have a machine with the resources to run + postgres, and would rather only maintain a single DBMS. We're stuck with + SQL Server because pretty much all the company's custom applications + (written by consultants) are locked into SQL Server 2000. I can imagine + this scenario is fairly common, and it would be nice to use the existing + properly specced database server for storing Bacula's catalog, rather + than having to run a second DBMS. + + +Item n: Split documentation + Origin: Maxx + Date: 27th July 2006 + Status: + + What: Split documentation in several books + + Why: Bacula manual has now more than 600 pages, and looking for + implementation details is getting complicated. I think + it would be good to split the single volume in two or + maybe three parts: + + 1) Introduction, requirements and tutorial, typically + are useful only until first installation time + + 2) Basic installation and configuration, with all the + gory details about the directives supported 3) + Advanced Bacula: testing, troubleshooting, GUI and + ancillary programs, security managements, scripting, + etc. + + Notes: + diff --git a/bacula/scripts/disk-changer.in b/bacula/scripts/disk-changer.in index c66799b50e..7cba06acf4 100644 --- a/bacula/scripts/disk-changer.in +++ b/bacula/scripts/disk-changer.in @@ -108,6 +108,11 @@ check_parm_count() { get_dir() { bn=`basename $device` dir=`echo "$device" | sed -e s%/$bn%%g -` + if [ ! -d $dir ]; then + echo "ERROR: Autochanger directory \"$dir\" does not exist.\n" + echo " You must create it.\n" + exit 1 + fi } diff --git a/bacula/src/cats/bdb.c b/bacula/src/cats/bdb.c index 43cc175e2b..3aa57c220d 100644 --- a/bacula/src/cats/bdb.c +++ b/bacula/src/cats/bdb.c @@ -462,4 +462,8 @@ db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { } +int db_int64_handler(void *ctx, int num_fields, char **row) +{ return 0; } + + #endif /* HAVE_BACULA_DB */ diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index a196701e30..1d47ae6d06 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -786,19 +786,24 @@ struct FILESET_DBR { bool created; /* set when record newly created */ }; +/* Call back context for getting a 32/64 bit value from the database */ +struct db_int64_ctx { + int64_t value; /* value returned */ + int count; /* number of values seen */ +}; #include "protos.h" #include "jcr.h" /* - * Some functions exported by sql.c for use withing the + * Some functions exported by sql.c for use within the * cats directory. */ void list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type); void list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx); int get_sql_record_max(JCR *jcr, B_DB *mdb); -int check_tables_version(JCR *jcr, B_DB *mdb); +bool check_tables_version(JCR *jcr, B_DB *mdb); void _db_unlock(const char *file, int line, B_DB *mdb); void _db_lock(const char *file, int line, B_DB *mdb); diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index dcc84f7cb8..646c447157 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -39,6 +39,7 @@ int db_next_index(JCR *jcr, B_DB *mdb, char *table, char *index); int db_sql_query(B_DB *mdb, const char *cmd, DB_RESULT_HANDLER *result_handler, void *ctx); void db_start_transaction(JCR *jcr, B_DB *mdb); void db_end_transaction(JCR *jcr, B_DB *mdb); +int db_int64_handler(void *ctx, int num_fields, char **row); /* create.c */ diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index d1ab642672..0ee91f8847 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -60,6 +60,21 @@ static int int_handler(void *ctx, int num_fields, char **row) return 0; } +/* + * Called here to retrieve a 32/64 bit integer from the database. + * The returned integer will be extended to 64 bit. + */ +int db_int64_handler(void *ctx, int num_fields, char **row) +{ + db_int64_ctx *lctx = (db_int64_ctx *)ctx; + + if (row[0]) { + lctx->value = str_to_int64(row[0]); + lctx->count++; + } + return 0; +} + /* NOTE!!! The following routines expect that the @@ -67,7 +82,7 @@ static int int_handler(void *ctx, int num_fields, char **row) */ /* Check that the tables correspond to the version we want */ -int check_tables_version(JCR *jcr, B_DB *mdb) +bool check_tables_version(JCR *jcr, B_DB *mdb) { const char *query = "SELECT VersionId FROM Version"; @@ -75,14 +90,15 @@ int check_tables_version(JCR *jcr, B_DB *mdb) if (!db_sql_query(mdb, query, int_handler, (void *)&bacula_db_version)) { Mmsg(mdb->errmsg, "Database not created or server not running.\n"); Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); + return false; } if (bacula_db_version != BDB_VERSION) { Mmsg(mdb->errmsg, "Version error for database \"%s\". Wanted %d, got %d\n", mdb->db_name, BDB_VERSION, bacula_db_version); Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); - return 0; + return false; } - return 1; + return true; } /* Utility routine for queries. The database MUST be locked before calling here. */ diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index 75b1c8b163..3dd8a58212 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -282,8 +282,8 @@ void catalog_request(JCR *jcr, BSOCK *bs) &jm.FirstIndex, &jm.LastIndex, &jm.StartFile, &jm.EndFile, &jm.StartBlock, &jm.EndBlock, &jm.Copy, &Stripe) == 9) { - if (jcr->previous_jcr) { - jm.JobId = jcr->previous_jcr->JobId; + if (jcr->mig_jcr) { + jm.JobId = jcr->mig_jcr->JobId; jm.MediaId = jcr->MediaId; } else { jm.JobId = jcr->JobId; @@ -397,8 +397,8 @@ void catalog_update(JCR *jcr, BSOCK *bs) ar->FileIndex = FileIndex; ar->Stream = Stream; ar->link = NULL; - if (jcr->previous_jcr) { - ar->JobId = jcr->previous_jcr->JobId; + if (jcr->mig_jcr) { + ar->JobId = jcr->mig_jcr->JobId; } else { ar->JobId = jcr->JobId; } diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 6695df9085..e77ccdeaae 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -463,8 +463,8 @@ public: uint32_t MaxVolFiles; /* Maximum files on the Volume */ uint64_t MaxVolBytes; /* Maximum bytes on the Volume */ utime_t MigrationTime; /* Time to migrate to next pool */ - uint32_t MigrationHighBytes; /* When migration starts */ - uint32_t MigrationLowBytes; /* When migration stops */ + uint64_t MigrationHighBytes; /* When migration starts */ + uint64_t MigrationLowBytes; /* When migration stops */ POOL *NextPool; /* Next pool for migration */ alist *storage; /* Where is device -- list of Storage to be used */ bool use_catalog; /* maintain catalog for media */ diff --git a/bacula/src/dird/migrate.c b/bacula/src/dird/migrate.c index e30fb29650..20e6078235 100644 --- a/bacula/src/dird/migrate.c +++ b/bacula/src/dird/migrate.c @@ -45,6 +45,9 @@ static bool get_job_to_migrate(JCR *jcr); struct idpkt; static bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1, const char *query2, const char *type); +static bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1, + const char *type); +static bool find_jobids_from_mediaid_list(JCR *jcr, idpkt *ids, const char *type); static void start_migration_job(JCR *jcr); /* @@ -98,8 +101,22 @@ bool do_migration(JCR *jcr) char ed1[100]; BSOCK *sd; JOB *job, *prev_job; - JCR *prev_jcr; /* newly migrated job */ + JCR *mig_jcr; /* newly migrated job */ + /* + * previous_jr refers to the job DB record of the Job that is + * being migrated. + * prev_job refers to the job resource of the Job that is + * being migrated. + * jcr is the jcr for the current "migration" job. It is a + * control job that is put in the DB as a migration job, which + * means that this job migrated a previous job to a new job. + * mig_jcr refers to the newly migrated job that is run by + * the current jcr. It is a backup job that moves (migrates) the + * data written for the previous_jr into the new pool. This + * job (mig_jcr) becomes the new backup job that replaces + * the original backup job. + */ if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) { set_jcr_job_status(jcr, JS_Terminated); migration_cleanup(jcr, jcr->JobStatus); @@ -122,39 +139,34 @@ bool do_migration(JCR *jcr) return false; } - /* - * prev_jcr is the new Job that corresponds to the original - * 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 prev_jcr. - */ - prev_jcr = jcr->previous_jcr = new_jcr(sizeof(JCR), dird_free_jcr); - memcpy(&prev_jcr->previous_jr, &jcr->previous_jr, sizeof(prev_jcr->previous_jr)); + mig_jcr = jcr->mig_jcr = new_jcr(sizeof(JCR), dird_free_jcr); + memcpy(&mig_jcr->previous_jr, &jcr->previous_jr, sizeof(mig_jcr->previous_jr)); - /* Turn the prev_jcr into a "real" job */ - set_jcr_defaults(prev_jcr, prev_job); - if (!setup_job(prev_jcr)) { + /* Turn the mig_jcr into a "real" job that takes on the aspects of + * the previous backup job "prev_job". + */ + set_jcr_defaults(mig_jcr, prev_job); + if (!setup_job(mig_jcr)) { return false; } /* Now reset the job record from the previous job */ - memcpy(&prev_jcr->jr, &jcr->previous_jr, sizeof(prev_jcr->jr)); + memcpy(&mig_jcr->jr, &jcr->previous_jr, sizeof(mig_jcr->jr)); /* Update the jr to reflect the new values of PoolId, FileSetId, and JobId. */ - prev_jcr->jr.PoolId = jcr->jr.PoolId; - prev_jcr->jr.FileSetId = jcr->jr.FileSetId; - prev_jcr->jr.JobId = prev_jcr->JobId; + mig_jcr->jr.PoolId = jcr->jr.PoolId; + mig_jcr->jr.FileSetId = jcr->jr.FileSetId; + mig_jcr->jr.JobId = mig_jcr->JobId; - Dmsg4(dbglevel, "Prev_jcr: Name=%s JobId=%d Type=%c Level=%c\n", - prev_jcr->jr.Name, prev_jcr->jr.JobId, - prev_jcr->jr.JobType, prev_jcr->jr.JobLevel); + Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n", + mig_jcr->jr.Name, mig_jcr->jr.JobId, + mig_jcr->jr.JobType, mig_jcr->jr.JobLevel); /* * Get the PoolId used with the original job. Then * find the pool name from the database record. */ memset(&pr, 0, sizeof(pr)); - pr.PoolId = prev_jcr->previous_jr.PoolId; + pr.PoolId = mig_jcr->previous_jr.PoolId; if (!db_get_pool_record(jcr, jcr->db, &pr)) { Jmsg(jcr, M_FATAL, 0, _("Pool for JobId %s not in database. ERR=%s\n"), edit_int64(pr.PoolId, ed1), db_strerror(jcr->db)); @@ -167,11 +179,8 @@ bool do_migration(JCR *jcr) return false; } - /* Check Migration time and High/Low water marks */ - /* ***FIXME*** */ - /* If pool storage specified, use it for restore */ - copy_rstorage(prev_jcr, pool->storage, _("Pool resource")); + copy_rstorage(mig_jcr, pool->storage, _("Pool resource")); copy_rstorage(jcr, pool->storage, _("Pool resource")); /* If the original backup pool has a NextPool, make sure a @@ -186,8 +195,8 @@ bool do_migration(JCR *jcr) * put the "NextPool" resource pointer in our jcr so that we * can pull the Storage reference from it. */ - prev_jcr->pool = jcr->pool = pool->NextPool; - prev_jcr->jr.PoolId = jcr->jr.PoolId; + mig_jcr->pool = jcr->pool = pool->NextPool; + mig_jcr->jr.PoolId = jcr->jr.PoolId; pm_strcpy(jcr->pool_source, _("NextPool in Pool resource")); } @@ -199,7 +208,7 @@ bool do_migration(JCR *jcr) edit_uint64(jcr->JobId, ed1), jcr->Job); set_jcr_job_status(jcr, JS_Running); - set_jcr_job_status(prev_jcr, JS_Running); + set_jcr_job_status(mig_jcr, JS_Running); Dmsg2(dbglevel, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel); /* Update job start record for this migration job */ @@ -208,13 +217,13 @@ bool do_migration(JCR *jcr) return false; } - Dmsg4(dbglevel, "Prev_jcr: Name=%s JobId=%d Type=%c Level=%c\n", - prev_jcr->jr.Name, prev_jcr->jr.JobId, - prev_jcr->jr.JobType, prev_jcr->jr.JobLevel); + Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n", + mig_jcr->jr.Name, mig_jcr->jr.JobId, + mig_jcr->jr.JobType, mig_jcr->jr.JobLevel); /* Update job start record for migrated job */ - if (!db_update_job_start_record(prev_jcr, prev_jcr->db, &prev_jcr->jr)) { - Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(prev_jcr->db)); + if (!db_update_job_start_record(mig_jcr, mig_jcr->db, &mig_jcr->jr)) { + Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(mig_jcr->db)); return false; } @@ -227,7 +236,7 @@ bool do_migration(JCR *jcr) */ Dmsg0(110, "Open connection with storage daemon\n"); set_jcr_job_status(jcr, JS_WaitSD); - set_jcr_job_status(prev_jcr, JS_WaitSD); + set_jcr_job_status(mig_jcr, JS_WaitSD); /* * Start conversation with Storage daemon */ @@ -264,7 +273,7 @@ bool do_migration(JCR *jcr) set_jcr_job_status(jcr, JS_Running); - set_jcr_job_status(prev_jcr, JS_Running); + set_jcr_job_status(mig_jcr, JS_Running); /* Pickup Job termination data */ /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/Errors */ @@ -275,7 +284,7 @@ bool do_migration(JCR *jcr) return false; } migration_cleanup(jcr, jcr->JobStatus); - if (prev_jcr) { + if (mig_jcr) { UAContext *ua = new_ua_context(jcr); purge_files_from_job(ua, jcr->previous_jr.JobId); free_ua_context(ua); @@ -365,7 +374,7 @@ const char *sql_jobids_from_client = /* Get Volume names in Pool */ const char *sql_vol = "SELECT DISTINCT VolumeName FROM Media,Pool WHERE" - " VolStatus in ('Full','Used','Error') AND" + " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND" " Media.PoolId=Pool.PoolId AND Pool.Name='%s'"; /* Get JobIds from regex'ed Volume names */ @@ -374,23 +383,21 @@ const char *sql_jobids_from_vol = " WHERE Media.VolumeName='%s' AND Media.MediaId=JobMedia.MediaId" " AND JobMedia.JobId=Job.JobId" " ORDER by Job.StartTime"; - - - const char *sql_smallest_vol = "SELECT MediaId FROM Media,Pool WHERE" - " VolStatus in ('Full','Used','Error') AND" + " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND" " Media.PoolId=Pool.PoolId AND Pool.Name='%s'" " ORDER BY VolBytes ASC LIMIT 1"; const char *sql_oldest_vol = "SELECT MediaId FROM Media,Pool WHERE" - " VolStatus in ('Full','Used','Error') AND" + " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND" " Media.PoolId=Pool.PoolId AND Pool.Name='%s'" " ORDER BY LastWritten ASC LIMIT 1"; +/* Get JobIds when we have selected MediaId */ const char *sql_jobids_from_mediaid = "SELECT DISTINCT Job.JobId,Job.StartTime FROM JobMedia,Job" " WHERE JobMedia.JobId=Job.JobId AND JobMedia.MediaId=%s" @@ -398,12 +405,12 @@ const char *sql_jobids_from_mediaid = const char *sql_pool_bytes = "SELECT SUM(VolBytes) FROM Media,Pool WHERE" - " VolStatus in ('Full','Used','Error','Append') AND" + " VolStatus in ('Full','Used','Error','Append') AND Media.Enabled=1 AND" " Media.PoolId=Pool.PoolId AND Pool.Name='%s'"; const char *sql_vol_bytes = "SELECT MediaId FROM Media,Pool WHERE" - " VolStatus in ('Full','Used','Error') AND" + " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND" " Media.PoolId=Pool.PoolId AND Pool.Name='%s' AND" " VolBytes<%s ORDER BY LastWritten ASC LIMIT 1"; @@ -467,22 +474,36 @@ static bool get_job_to_migrate(JCR *jcr) goto bail_out; } break; - - -/***** Below not implemented yet *********/ case MT_SMALLEST_VOL: - Mmsg(query, sql_smallest_vol, jcr->pool->hdr.name); -// Mmsg(query2, sql_jobids_from_mediaid, JobIds); -// Dmsg1(000, "Smallest Vol Jobids=%s\n", JobIds); + if (!find_mediaid_then_jobids(jcr, &ids, sql_smallest_vol, "Smallest Volume")) { + goto bail_out; + } break; case MT_OLDEST_VOL: - Mmsg(query, sql_oldest_vol, jcr->pool->hdr.name); -// Mmsg(query2, sql_jobids_from_mediaid, JobIds); -// Dmsg1(000, "Oldest Vol Jobids=%s\n", JobIds); + if (!find_mediaid_then_jobids(jcr, &ids, sql_oldest_vol, "Oldest Volume")) { + goto bail_out; + } break; + +/***** Below not implemented yet *********/ case MT_POOL_OCCUPANCY: + db_int64_ctx ctx; + + ctx.count = 0; Mmsg(query, sql_pool_bytes, jcr->pool->hdr.name); -// Dmsg1(000, "Pool Occupancy Jobids=%s\n", JobIds); + if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) { + Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); + goto bail_out; + } + if (ctx.count == 0) { + Jmsg(jcr, M_INFO, 0, _("No Volumes found to migrate.\n")); + goto bail_out; + } + if (ctx.value > (int64_t)jcr->pool->MigrationHighBytes) { + Dmsg2(000, "highbytes=%d pool=%d\n", (int)jcr->pool->MigrationHighBytes, + (int)ctx.value); + } + goto bail_out; break; case MT_POOL_TIME: Dmsg0(000, "Pool time not implemented\n"); @@ -566,9 +587,57 @@ static void start_migration_job(JCR *jcr) free_ua_context(ua); } +static bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1, + const char *type) +{ + bool ok = false; + POOL_MEM query(PM_MESSAGE); + + ids->count = 0; + /* Basic query for MediaId */ + Mmsg(query, query1, jcr->pool->hdr.name); + if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) { + Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); + goto bail_out; + } + if (ids->count == 0) { + Jmsg(jcr, M_INFO, 0, _("No %ss found to migrate.\n"), type); + } + if (ids->count != 1) { + Jmsg(jcr, M_FATAL, 0, _("SQL logic error. Count should be 1 but is %d\n"), + ids->count); + goto bail_out; + } + Dmsg1(000, "Smallest Vol Jobids=%s\n", ids->list); + + ok = find_jobids_from_mediaid_list(jcr, ids, type); + +bail_out: + return ok; +} + +static bool find_jobids_from_mediaid_list(JCR *jcr, idpkt *ids, const char *type) +{ + bool ok = false; + POOL_MEM query(PM_MESSAGE); + + Mmsg(query, sql_jobids_from_mediaid, ids->list); + ids->count = 0; + if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) { + Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); + goto bail_out; + } + if (ids->count == 0) { + Jmsg(jcr, M_INFO, 0, _("No %ss found to migrate.\n"), type); + } + ok = true; +bail_out: + return ok; +} static bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1, - const char *query2, const char *type) { + const char *query2, const char *type) +{ dlist *item_chain; uitem *item = NULL; uitem *last_item = NULL; @@ -667,7 +736,7 @@ void migration_cleanup(JCR *jcr, int TermCode) MEDIA_DBR mr; double kbps; utime_t RunTime; - JCR *prev_jcr = jcr->previous_jcr; + JCR *mig_jcr = jcr->mig_jcr; POOL_MEM query(PM_MESSAGE); Dmsg2(100, "Enter migrate_cleanup %d %c\n", TermCode, TermCode); @@ -678,33 +747,33 @@ void migration_cleanup(JCR *jcr, int TermCode) /* * Check if we actually did something. - * prev_jcr is jcr of the newly migrated job. + * mig_jcr is jcr of the newly migrated job. */ - if (prev_jcr) { - prev_jcr->JobFiles = jcr->JobFiles = jcr->SDJobFiles; - prev_jcr->JobBytes = jcr->JobBytes = jcr->SDJobBytes; - prev_jcr->VolSessionId = jcr->VolSessionId; - prev_jcr->VolSessionTime = jcr->VolSessionTime; - prev_jcr->jr.RealEndTime = 0; - prev_jcr->jr.PriorJobId = jcr->previous_jr.JobId; + if (mig_jcr) { + mig_jcr->JobFiles = jcr->JobFiles = jcr->SDJobFiles; + mig_jcr->JobBytes = jcr->JobBytes = jcr->SDJobBytes; + mig_jcr->VolSessionId = jcr->VolSessionId; + mig_jcr->VolSessionTime = jcr->VolSessionTime; + mig_jcr->jr.RealEndTime = 0; + mig_jcr->jr.PriorJobId = jcr->previous_jr.JobId; - set_jcr_job_status(prev_jcr, TermCode); + set_jcr_job_status(mig_jcr, TermCode); - update_job_end_record(prev_jcr); + update_job_end_record(mig_jcr); /* Update final items to set them to the previous job's values */ Mmsg(query, "UPDATE Job SET StartTime='%s',EndTime='%s'," "JobTDate=%s WHERE JobId=%s", jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime, edit_uint64(jcr->previous_jr.JobTDate, ec1), - edit_uint64(prev_jcr->jr.JobId, ec2)); - db_sql_query(prev_jcr->db, query.c_str(), NULL, NULL); + edit_uint64(mig_jcr->jr.JobId, ec2)); + db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL); /* Now marke the previous job as migrated */ Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s", (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1)); - db_sql_query(prev_jcr->db, query.c_str(), NULL, NULL); + db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL); if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_WARNING, 0, _("Error getting job record for stats: %s"), @@ -719,9 +788,9 @@ void migration_cleanup(JCR *jcr, int TermCode) set_jcr_job_status(jcr, JS_ErrorTerminated); } - update_bootstrap_file(prev_jcr); + update_bootstrap_file(mig_jcr); - if (!db_get_job_volume_names(prev_jcr, prev_jcr->db, prev_jcr->jr.JobId, &prev_jcr->VolumeName)) { + if (!db_get_job_volume_names(mig_jcr, mig_jcr->db, mig_jcr->jr.JobId, &mig_jcr->VolumeName)) { /* * Note, if the job has erred, most likely it did not write any * tape, so suppress this "error" message since in that case @@ -729,9 +798,9 @@ void migration_cleanup(JCR *jcr, int TermCode) * normal exit should we complain about this error. */ if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) { - Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(prev_jcr->db)); + Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(mig_jcr->db)); } - prev_jcr->VolumeName[0] = 0; /* none */ + mig_jcr->VolumeName[0] = 0; /* none */ } } @@ -808,8 +877,8 @@ void migration_cleanup(JCR *jcr, int TermCode) VERSION, LSMDATE, edt, - prev_jcr ? edit_uint64(jcr->previous_jr.JobId, ec6) : "0", - prev_jcr ? edit_uint64(prev_jcr->jr.JobId, ec7) : "0", + mig_jcr ? edit_uint64(jcr->previous_jr.JobId, ec6) : "0", + mig_jcr ? edit_uint64(mig_jcr->jr.JobId, ec7) : "0", edit_uint64(jcr->jr.JobId, ec8), jcr->jr.Job, level_to_str(jcr->JobLevel), jcr->since, @@ -825,7 +894,7 @@ void migration_cleanup(JCR *jcr, int TermCode) edit_uint64_with_commas(jcr->SDJobBytes, ec2), edit_uint64_with_suffix(jcr->SDJobBytes, ec3), (float)kbps, - prev_jcr ? prev_jcr->VolumeName : "", + mig_jcr ? mig_jcr->VolumeName : "", jcr->VolSessionId, jcr->VolSessionTime, edit_uint64_with_commas(mr.VolBytes, ec4), @@ -834,10 +903,10 @@ void migration_cleanup(JCR *jcr, int TermCode) sd_term_msg, term_code); - Dmsg1(100, "migrate_cleanup() previous_jcr=0x%x\n", jcr->previous_jcr); - if (jcr->previous_jcr) { - free_jcr(jcr->previous_jcr); - jcr->previous_jcr = NULL; + Dmsg1(100, "migrate_cleanup() mig_jcr=0x%x\n", jcr->mig_jcr); + if (jcr->mig_jcr) { + free_jcr(jcr->mig_jcr); + jcr->mig_jcr = NULL; } Dmsg0(100, "Leave migrate_cleanup()\n"); } diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index c8100a12bf..a7f3fd88a9 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -1328,14 +1328,14 @@ static int backup_cmd(JCR *jcr) } else { /* tell user if snapshot creation of a specific drive failed */ int i; - for (i=0; i < strlen(szWinDriveLetters); i++) { + for (i=0; i < (int)strlen(szWinDriveLetters); i++) { if (islower(szWinDriveLetters[i])) { Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive \"%c:\\\" failed. VSS support is disabled on this drive.\n"), szWinDriveLetters[i]); jcr->Errors++; } } /* inform user about writer states */ - for (i=0; iGetWriterCount(); i++) + for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) if (g_pVSSClient->GetWriterState(i) < 1) { Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i)); jcr->Errors++; diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 20630005f0..f37b6f6865 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -214,7 +214,7 @@ public: JOB_DBR jr; /* Job DB record for current job */ JOB_DBR previous_jr; /* previous job database record */ JOB *previous_job; /* Job resource of migration previous job */ - JCR *previous_jcr; /* previous job control record */ + JCR *mig_jcr; /* JCR for migration/copy job */ char FSCreateTime[MAX_TIME_LENGTH]; /* FileSet CreateTime as returned from DB */ char since[MAX_TIME_LENGTH]; /* since time */ union { diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 0500692c01..fd5e49236f 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -751,6 +751,12 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) Pmsg0(000, _("Got Prog Data Stream record.\n")); } break; + + case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL: /* Standard ACL attributes on UNIX */ + case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL: /* Default ACL attributes on UNIX */ + /* Ignore Unix attributes */ + break; + default: Pmsg2(0, _("Unknown stream type!!! stream=%d data=%s\n"), rec->Stream, rec->data); break; diff --git a/bacula/src/version.h b/bacula/src/version.h index 81709076ae..9c9d33c459 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -3,9 +3,9 @@ */ #undef VERSION -#define VERSION "1.39.17" -#define BDATE "27 July 2006" -#define LSMDATE "27Jul06" +#define VERSION "1.39.18" +#define BDATE "30 July 2006" +#define LSMDATE "30Jul06" /* Debug flags */ #undef DEBUG diff --git a/bacula/src/win32/.cvsignore b/bacula/src/win32/.cvsignore index 1fa8778710..456d4631bc 100644 --- a/bacula/src/win32/.cvsignore +++ b/bacula/src/win32/.cvsignore @@ -9,3 +9,7 @@ bacula.suo 2 3 mingwm10.dll +Makefile.vcpp +winbacula.nsi +winres.res +wx-console.res diff --git a/bacula/src/win32/pebuilder/.cvsignore b/bacula/src/win32/pebuilder/.cvsignore index e69de29bb2..f3c7a7c5da 100644 --- a/bacula/src/win32/pebuilder/.cvsignore +++ b/bacula/src/win32/pebuilder/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/bacula/src/win32/wx-console/.cvsignore b/bacula/src/win32/wx-console/.cvsignore index cabf2720ba..0cce7b7ef3 100644 --- a/bacula/src/win32/wx-console/.cvsignore +++ b/bacula/src/win32/wx-console/.cvsignore @@ -1,3 +1,4 @@ *.idb *.d *.res +wx-console.conf -- 2.39.5