From: Kern Sibbald Date: Fri, 17 Oct 2003 08:07:07 +0000 (+0000) Subject: Commit final code for 1.32b + Verify Job (name) + change Pool for a Volume X-Git-Tag: Release-7.0.0~9957 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=7e4f21a4f818abe5ac5a5eef0552f56e0be9e235;p=bacula%2Fbacula Commit final code for 1.32b + Verify Job (name) + change Pool for a Volume git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@750 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/ChangeLog b/bacula/ChangeLog index a3d3462278..c06d96429a 100644 --- a/bacula/ChangeLog +++ b/bacula/ChangeLog @@ -1,5 +1,18 @@ -2003-10-10 Version 1.32b 10Oct03 Release +2003-10-15 Version 1.32b 14Oct03 Release +14Oct03 +- Modify configure so that if threaded MySQL client library + is not present, Bacula will link with the non-threaded + version. +- Updates to the Web pages and to the manual. +- Remove trademark symbol from title. Phil pointed out that it + does not display correctly in a title. +11Oct03 +- Implement restore by file before date. +- Change restore arguments a bit so that you can feed it + multiple jobid= specifications or multiple file= specifications. +- Pass restore with run option on to run_cmd. +- Make run-cmd not prompt if it has a "run" on the command line. 10Oct03 - When pruning, select only old orphanned jobs to delete so that the current job is not pruned too. diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index 3220ac2652..4831d591b5 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -1,14 +1,18 @@ Release Notes for Bacula 1.32b - Bacula code: Total files = 259 Total lines = 77,984 (*.h *.c *.in) + Bacula code: Total files = 259 Total lines = 78,067 (*.h *.c *.in) -Changes since 1.32a: +Most Significant Changes since 1.32a: - Improve forward space file/block during restore, many optimizations. - Fix a bug that did not allow appending to a tape on FreeBSD systems. - Fix pruning so that it will not prune the current job. +- Modify configure to use non-threaded MySQL client lib if + the threaded version is not present. +- Implement restore by file before date. +- When pruning don't prune the current job. Major Changes 1.32a Release: - Implemented forward space file/block whenever possible diff --git a/bacula/autoconf/acconfig.h b/bacula/autoconf/acconfig.h index a6fe066c74..e9cef42055 100644 --- a/bacula/autoconf/acconfig.h +++ b/bacula/autoconf/acconfig.h @@ -23,6 +23,9 @@ /* Define if you want to use MySQL */ #undef HAVE_MYSQL +/* Defined if MySQL thread safe library is present */ +#undef HAVE_THREAD_SAFE_MYSQL + /* Define if you want to use embedded MySQL */ #undef HAVE_EMBEDDED_MYSQL @@ -204,4 +207,3 @@ #undef HAVE_OLD_SOCKOPT #undef HAVE_BIGENDIAN - diff --git a/bacula/autoconf/aclocal.m4 b/bacula/autoconf/aclocal.m4 index 8f0aab87b2..b5f4b4d889 100644 --- a/bacula/autoconf/aclocal.m4 +++ b/bacula/autoconf/aclocal.m4 @@ -390,7 +390,12 @@ Which DBMS do you want to use (please select only one): fi fi SQL_INCLUDE=-I$MYSQL_INCDIR - SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient_r -lz" + if test -f $MYSQL_LIBDIR/libmysqlclient_r.a; then + SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient_r -lz" + AC_DEFINE(HAVE_THREAD_SAFE_MYSQL) + else + SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient -lz" + fi SQL_BINDIR=$MYSQL_BINDIR AC_DEFINE(HAVE_MYSQL) diff --git a/bacula/autoconf/config.h.in b/bacula/autoconf/config.h.in index 13c47a8636..db3f80dc3c 100644 --- a/bacula/autoconf/config.h.in +++ b/bacula/autoconf/config.h.in @@ -24,6 +24,9 @@ /* Define if you want to use MySQL */ #undef HAVE_MYSQL +/* Defined if MySQL thread safe library is present */ +#undef HAVE_THREAD_SAFE_MYSQL + /* Define if you want to use embedded MySQL */ #undef HAVE_EMBEDDED_MYSQL @@ -205,7 +208,6 @@ #undef HAVE_BIGENDIAN - /* Define to 1 if the `closedir' function returns void instead of `int'. */ #undef CLOSEDIR_VOID diff --git a/bacula/configure b/bacula/configure index ee3fafe7e5..56b9244a7f 100755 --- a/bacula/configure +++ b/bacula/configure @@ -6734,7 +6734,15 @@ echo "$as_me: error: Invalid MySQL directory $withval - unable to find mysql.h u fi fi SQL_INCLUDE=-I$MYSQL_INCDIR - SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient_r -lz" + if test -f $MYSQL_LIBDIR/libmysqlclient_r.a; then + SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient_r -lz" + cat >>confdefs.h <<\_ACEOF +#define HAVE_THREAD_SAFE_MYSQL 1 +_ACEOF + + else + SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient -lz" + fi SQL_BINDIR=$MYSQL_BINDIR cat >>confdefs.h <<\_ACEOF diff --git a/bacula/kernstodo b/bacula/kernstodo index 582aa56831..0095e2ba2d 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -36,13 +36,19 @@ For 1.33 Testing/Documentation: SuSE. For 1.33 +- Add VerifyJob to "run" summary (yes/mod/no) prompt. +- Add device name to "Current Volume not acceptable because ..." +- Make sure that Bacula rechecks the tape after the 20 min wait. +- Set IO_NOWAIT on Bacula packets +- Try doing a raw partition backup and restore by mounting a + Windows partition. +- Implement Verify=DiskToCatalog +- Implement a RunAfterFailedJob - Report CVS problems to SourceForge. - Implement .consolerc for Console -- I want to restore by file to some date. - Is it really important to make Job name the same to find the Full backup to avoid promoting an Incremental job? - Start label, then run job when tape labeled, it should broadcast. -- Implement a RunAfterFailedJob - Zap illegal characters in job name for mail files (e.g. /). - From Lars Köllers: Yes, it would allow to highly automatic the request for new tapes. If a @@ -107,7 +113,6 @@ For 1.33 - Make sure a rescheduled job is properly reported by status. - Walk through the Pool records rather than the Job records in dird.c to create/update pools. -- Figure out a way to move Volumes from one pool to another. - What to do about "list files job=xxx". - Implement delete Job. - Document need to put LabelFormat in quotes. @@ -1044,3 +1049,6 @@ Done: (see kernsdone for more) - Test connect timeouts. - Fix FreeBSD build with tcp_wrapper -- should not have -lnsl - Implement fast block rejection. +- I want to restore by file to some date. +---- 1.32b released +- Figure out a way to move Volumes from one pool to another. diff --git a/bacula/src/cats/mysql.c b/bacula/src/cats/mysql.c index 3b474819b0..719aab5cd8 100644 --- a/bacula/src/cats/mysql.c +++ b/bacula/src/cats/mysql.c @@ -176,7 +176,9 @@ It is probably not running or your password is incorrect.\n"), return 0; } +#ifdef HAVE_TREAD_SAFE_MYSQL my_thread_init(); +#endif mdb->connected = TRUE; V(mutex); @@ -188,7 +190,9 @@ db_close_database(JCR *jcr, B_DB *mdb) { P(mutex); mdb->ref_count--; +#ifdef HAVE_TREAD_SAFE_MYSQL my_thread_end(); +#endif if (mdb->ref_count == 0) { qdchain(&mdb->bq); if (mdb->connected && mdb->db) { diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 6ce3efee0c..ab233e474a 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -61,7 +61,7 @@ int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr); /* find.c */ int db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime); -int db_find_last_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr); +int db_find_last_jobid(JCR *jcr, B_DB *mdb, char *Name, JOB_DBR *jr); int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, MEDIA_DBR *mr); /* get.c */ @@ -69,7 +69,7 @@ int 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); int db_get_job_volume_names(JCR *jcr, B_DB *mdb, uint32_t JobId, POOLMEM **VolumeNames); -int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fdbr); +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); int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr); int db_get_num_media_records(JCR *jcr, B_DB *mdb); diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index c0379235f8..e29ea40110 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -144,7 +144,7 @@ db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime) * 0 on failure */ int -db_find_last_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr) +db_find_last_jobid(JCR *jcr, B_DB *mdb, char *Name, JOB_DBR *jr) { SQL_ROW row; @@ -156,10 +156,15 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr) "ClientId=%u ORDER BY StartTime DESC LIMIT 1", L_VERIFY_INIT, jr->Name, jr->ClientId); } else if (jr->Level == L_VERIFY_VOLUME_TO_CATALOG) { - Mmsg(&mdb->cmd, + if (Name) { + Mmsg(&mdb->cmd, +"SELECT JobId FROM Job WHERE Type='B' AND JobStatus='T' AND " +"Name='%s' ORDER BY StartTime DESC LIMIT 1", Name); + } else { + Mmsg(&mdb->cmd, "SELECT JobId FROM Job WHERE Type='B' AND " -"ClientId=%u ORDER BY StartTime DESC LIMIT 1", - jr->ClientId); +"ClientId=%u ORDER BY StartTime DESC LIMIT 1", jr->ClientId); + } } else { Mmsg1(&mdb->errmsg, _("Unknown Job level=%c\n"), jr->Level); db_unlock(mdb); diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 7ff3a44fe6..43d9a3a118 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -48,7 +48,7 @@ */ /* Forward referenced functions */ -static int db_get_file_record(JCR *jcr, B_DB *mdb, FILE_DBR *fdbr); +static int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr); static int db_get_filename_record(JCR *jcr, B_DB *mdb); static int db_get_path_record(JCR *jcr, B_DB *mdb); @@ -67,7 +67,7 @@ extern void split_path_and_filename(JCR *jcr, B_DB *mdb, char *fname); * Returns: 0 on failure * 1 on success with the File record in FILE_DBR */ -int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fdbr) +int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr) { int stat; Dmsg1(20, "Enter get_file_from_catalog fname=%s \n", fname); @@ -79,7 +79,7 @@ int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fd fdbr->PathId = db_get_path_record(jcr, mdb); - stat = db_get_file_record(jcr, mdb, fdbr); + stat = db_get_file_record(jcr, mdb, jr, fdbr); db_unlock(mdb); @@ -99,15 +99,23 @@ int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, FILE_DBR *fd * "normal" if a new file is found during Verify. */ static -int db_get_file_record(JCR *jcr, B_DB *mdb, FILE_DBR *fdbr) +int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr) { SQL_ROW row; int stat = 0; - Mmsg(&mdb->cmd, -"SELECT FileId, LStat, MD5 from File where File.JobId=%u and File.PathId=%u and \ -File.FilenameId=%u", fdbr->JobId, fdbr->PathId, fdbr->FilenameId); - + if (jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) { + Mmsg(&mdb->cmd, +"SELECT FileId, LStat, MD5 FROM File,Job WHERE " +"File.JobId=Job.JobId AND File.PathId=%u AND " +"File.FilenameId=%u AND Job.Type='B' AND Job.JobSTATUS='T' AND " +"ClientId=%u ORDER BY StartTime DESC LIMIT 1", + fdbr->PathId, fdbr->FilenameId, jr->ClientId); + } else { + Mmsg(&mdb->cmd, +"SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%u AND File.PathId=%u AND " +"File.FilenameId=%u", fdbr->JobId, fdbr->PathId, fdbr->FilenameId); + } Dmsg3(050, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n", fdbr->JobId, fdbr->FilenameId, fdbr->PathId); diff --git a/bacula/src/dird/authenticate.c b/bacula/src/dird/authenticate.c index b41ca667c6..9ec6d81bf1 100644 --- a/bacula/src/dird/authenticate.c +++ b/bacula/src/dird/authenticate.c @@ -69,7 +69,7 @@ int authenticate_storage_daemon(JCR *jcr) } if (!cram_md5_get_auth(sd, jcr->store->password, ssl_need) || !cram_md5_auth(sd, jcr->store->password, ssl_need)) { - Jmsg0(jcr, M_FATAL, 0, _("Director and Storage daemon passwords not the same.\n")); + Jmsg0(jcr, M_FATAL, 0, _("Director and Storage daemon passwords or names not the same.\n")); return 0; } Dmsg1(116, ">stored: %s", sd->msg); @@ -106,7 +106,7 @@ int authenticate_file_daemon(JCR *jcr) } if (!cram_md5_get_auth(fd, jcr->client->password, ssl_need) || !cram_md5_auth(fd, jcr->client->password, ssl_need)) { - Jmsg(jcr, M_FATAL, 0, _("Director and File daemon passwords not the same.\n")); + Jmsg(jcr, M_FATAL, 0, _("Director and File daemon passwords or names not the same.\n")); return 0; } Dmsg1(116, ">filed: %s", fd->msg); diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 47c9f98581..a5b3ae2646 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -203,6 +203,7 @@ static struct res_items job_items[] = { {"pool", store_res, ITEM(res_job.pool), R_POOL, 0, 0}, {"client", store_res, ITEM(res_job.client), R_CLIENT, 0, 0}, {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, 0, 0}, + {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0}, {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0}, {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS}, {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0}, @@ -345,6 +346,7 @@ struct s_jl joblevels[] = { {"Catalog", L_VERIFY_CATALOG, JT_VERIFY}, {"InitCatalog", L_VERIFY_INIT, JT_VERIFY}, {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY}, + {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY}, {"Data", L_VERIFY_DATA, JT_VERIFY}, {NULL, 0} }; @@ -410,7 +412,7 @@ char *level_to_str(int level) void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...), void *sock) { URES *res = (URES *)reshdr; - int recurse = 1; + bool recurse = true; char ed1[100], ed2[100]; if (res == NULL) { @@ -419,7 +421,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... } if (type < 0) { /* no recursion */ type = - type; - recurse = 0; + recurse = false; } switch (type) { case R_DIRECTOR: @@ -527,6 +529,11 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... } else { sendit(sock, "!!! No Pool resource\n"); } + if (res->res_job.verify_job) { + sendit(sock, " --> "); + dump_resource(-R_JOB, (RES *)res->res_job.verify_job, sendit, sock); + } + break; if (res->res_job.messages) { sendit(sock, " --> "); dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock); @@ -919,12 +926,13 @@ void save_resource(int type, struct res_items *items, int pass) if ((res = (URES *)GetResWithName(R_JOB, res_all.res_dir.hdr.name)) == NULL) { Emsg1(M_ERROR_TERM, 0, "Cannot find Job resource %s\n", res_all.res_dir.hdr.name); } - res->res_job.messages = res_all.res_job.messages; - res->res_job.schedule = res_all.res_job.schedule; - res->res_job.client = res_all.res_job.client; - res->res_job.fileset = res_all.res_job.fileset; - res->res_job.storage = res_all.res_job.storage; - res->res_job.pool = res_all.res_job.pool; + res->res_job.messages = res_all.res_job.messages; + res->res_job.schedule = res_all.res_job.schedule; + res->res_job.client = res_all.res_job.client; + res->res_job.fileset = res_all.res_job.fileset; + res->res_job.storage = res_all.res_job.storage; + res->res_job.pool = res_all.res_job.pool; + res->res_job.verify_job = res_all.res_job.verify_job; if (res->res_job.JobType == 0) { Emsg1(M_ERROR_TERM, 0, "Job Type not defined for Job resource %s\n", res_all.res_dir.hdr.name); } diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 5c4aad6b66..bf3ee96271 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -207,6 +207,7 @@ struct JOB { FILESET *fileset; /* What to backup -- Fileset */ STORE *storage; /* Where is device -- Storage daemon */ POOL *pool; /* Where is media -- Media Pool */ + JOB *verify_job; /* Job name to verify */ uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ }; diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index c455d086b4..48e1d49a82 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -799,6 +799,26 @@ static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr) free_pool_memory(query); } +/* Modify the Pool in which this Volume is located */ +static void update_volpool(UAContext *ua, char *val, MEDIA_DBR *mr) +{ + POOL_DBR pr; + POOLMEM *query; + memset(&pr, 0, sizeof(pr)); + bstrncpy(pr.Name, val, sizeof(pr.Name)); + if (!get_pool_dbr(ua, &pr)) { + return; + } + query = get_pool_memory(PM_MESSAGE); + Mmsg(&query, "UPDATE Media SET PoolId=%u WHERE MediaId=%u", pr.PoolId, mr->MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, _("New Pool is: %s\n"), pr.Name); + } + free_pool_memory(query); +} + /* * Update a media record -- allows you to change the * Volume status. E.g. if you want Bacula to stop @@ -808,6 +828,7 @@ static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr) static int update_volume(UAContext *ua) { MEDIA_DBR mr; + POOL_DBR pr; POOLMEM *query; char ed1[30]; bool done = false; @@ -819,6 +840,7 @@ static int update_volume(UAContext *ua) N_("MaxVolFiles"), /* 4 */ N_("MaxVolBytes"), /* 5 */ N_("Recycle"), /* 6 */ + N_("Pool"), /* 7 */ NULL }; for (int i=0; kw[i]; i++) { @@ -849,6 +871,8 @@ static int update_volume(UAContext *ua) case 6: update_volrecycle(ua, ua->argv[j], &mr); break; + case 7: + update_volpool(ua, ua->argv[j], &mr); } done = true; } @@ -869,6 +893,7 @@ static int update_volume(UAContext *ua) add_prompt(ua, _("Recycle Flag")); add_prompt(ua, _("Slot")); add_prompt(ua, _("Volume Files")); + add_prompt(ua, _("Pool")); add_prompt(ua, _("Done")); switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) { case 0: /* Volume Status */ @@ -944,7 +969,6 @@ static int update_volume(UAContext *ua) case 7: /* Slot */ int slot; - POOL_DBR pr; memset(&pr, 0, sizeof(POOL_DBR)); pr.PoolId = mr.PoolId; @@ -999,6 +1023,19 @@ static int update_volume(UAContext *ua) free_pool_memory(query); break; + case 9: /* Volume's Pool */ + memset(&pr, 0, sizeof(POOL_DBR)); + pr.PoolId = mr.PoolId; + if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + return 0; + } + bsendmsg(ua, _("Current Pool is: %s\n"), pr.Name); + if (!get_cmd(ua, _("Enter new Pool name: "))) { + return 0; + } + update_volpool(ua, ua->cmd, &mr); + return 1; default: /* Done or error */ bsendmsg(ua, "Selection done.\n"); return 1; diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index 829e1e9a92..f54eaf22a3 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -557,6 +557,7 @@ Priority: %d\n"), add_prompt(ua, _("Initialize Catalog")); add_prompt(ua, _("Verify Catalog")); add_prompt(ua, _("Verify Volume to Catalog")); + add_prompt(ua, _("Verify Disk to Catalog")); add_prompt(ua, _("Verify Volume Data (not yet implemented)")); switch (do_prompt(ua, "", _("Select level"), NULL, 0)) { case 0: @@ -569,6 +570,9 @@ Priority: %d\n"), jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG; break; case 3: + jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG; + break; + case 4: jcr->JobLevel = L_VERIFY_DATA; break; default: diff --git a/bacula/src/dird/ua_tree.c b/bacula/src/dird/ua_tree.c index 29db4a832d..f09b7d5147 100644 --- a/bacula/src/dird/ua_tree.c +++ b/bacula/src/dird/ua_tree.c @@ -195,7 +195,7 @@ static void set_extract(UAContext *ua, TREE_NODE *node, TREE_CTX *tree, int valu tree_getpath(node, cwd, sizeof(cwd)); fdbr.FileId = 0; fdbr.JobId = node->JobId; - if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, &fdbr)) { + if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, NULL, &fdbr)) { int32_t LinkFI; decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */ /* @@ -338,7 +338,7 @@ static int dircmd(UAContext *ua, TREE_CTX *tree) tree_getpath(node, cwd, sizeof(cwd)); fdbr.FileId = 0; fdbr.JobId = node->JobId; - if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, &fdbr)) { + if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, NULL, &fdbr)) { int32_t LinkFI; decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */ ls_output(buf, cwd, node->extract, &statp); diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index 40faac1e41..213d8ddc5f 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -64,9 +64,9 @@ static int missing_handler(void *ctx, int num_fields, char **row); */ int do_verify(JCR *jcr) { - char *level; + char *level, *Name; BSOCK *fd; - JOB_DBR jr; + JOB_DBR jr, verify_jr; JobId_t JobId = 0; int stat; @@ -76,14 +76,23 @@ int do_verify(JCR *jcr) Dmsg1(9, "bdird: created client %s record\n", jcr->client->hdr.name); - /* If we are doing a verify from the catalog, - * we must look up the time and date of the - * last full verify. + /* + * Find JobId of last job that ran. E.g. + * for VERIFY_CATALOG we want the JobId of the last INIT. + * for VERIFY_VOLUME_TO_CATALOG, we want the JobId of the + * last backup Job. */ if (jcr->JobLevel == L_VERIFY_CATALOG || jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) { memcpy(&jr, &jcr->jr, sizeof(jr)); - if (!db_find_last_jobid(jcr, jcr->db, &jr)) { + if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG && + jcr->job->verify_job) { + Name = jcr->job->verify_job->hdr.name; + } else { + Name = NULL; + } + Dmsg1(100, "find last jobid for: %s\n", NPRT(Name)); + if (!db_find_last_jobid(jcr, jcr->db, Name, &jr)) { if (jcr->JobLevel == L_VERIFY_CATALOG) { Jmsg(jcr, M_FATAL, 0, _( "Unable to find JobId of previous InitCatalog Job.\n" @@ -96,7 +105,7 @@ int do_verify(JCR *jcr) goto bail_out; } JobId = jr.JobId; - Dmsg1(20, "Last full id=%d\n", JobId); + Dmsg1(100, "Last full Jobid=%d\n", JobId); } jcr->jr.JobId = jcr->JobId; @@ -111,28 +120,31 @@ int do_verify(JCR *jcr) jcr->fname = get_pool_memory(PM_FNAME); } - jcr->jr.JobId = JobId; /* save target JobId */ - /* Print Job Start message */ Jmsg(jcr, M_INFO, 0, _("Start Verify JobId %d Job=%s\n"), jcr->JobId, jcr->Job); + /* + * Now get the job record for the previous backup that interests + * us. We use the JobId that we found above. + */ if (jcr->JobLevel == L_VERIFY_CATALOG || - jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) { - memset(&jr, 0, sizeof(jr)); - jr.JobId = JobId; - if (!db_get_job_record(jcr, jcr->db, &jr)) { + jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG || + jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) { + memset(&verify_jr, 0, sizeof(verify_jr)); + verify_jr.JobId = JobId; + if (!db_get_job_record(jcr, jcr->db, &verify_jr)) { Jmsg(jcr, M_FATAL, 0, _("Could not get job record for previous Job. ERR=%s"), db_strerror(jcr->db)); goto bail_out; } - if (jr.JobStatus != 'T') { + if (verify_jr.JobStatus != 'T') { Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"), - JobId, jr.JobStatus); + JobId, verify_jr.JobStatus); goto bail_out; } Jmsg(jcr, M_INFO, 0, _("Verifying against JobId=%d Job=%s\n"), - JobId, jr.Job); + verify_jr.JobId, verify_jr.Job); } /* @@ -144,12 +156,12 @@ int do_verify(JCR *jcr) if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) { RBSR *bsr = new_bsr(); UAContext *ua; - bsr->JobId = jr.JobId; + bsr->JobId = verify_jr.JobId; ua = new_ua_context(jcr); complete_bsr(ua, bsr); bsr->fi = new_findex(); bsr->fi->findex = 1; - bsr->fi->findex2 = jr.JobFiles; + bsr->fi->findex2 = verify_jr.JobFiles; if (!write_bsr_file(ua, bsr)) { free_ua_context(ua); free_bsr(bsr); @@ -188,6 +200,13 @@ int do_verify(JCR *jcr) } else { jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */ } + + if (jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG && + jcr->job->verify_job) { + jcr->fileset = jcr->job->verify_job->fileset; + } + jcr->verify_jr = &verify_jr; + /* * OK, now connect to the File daemon * and ask him for the files. @@ -200,6 +219,7 @@ int do_verify(JCR *jcr) set_jcr_job_status(jcr, JS_Running); fd = jcr->file_bsock; + Dmsg0(30, ">filed: Send include list\n"); if (!send_include_list(jcr)) { goto bail_out; @@ -262,6 +282,9 @@ int do_verify(JCR *jcr) case L_VERIFY_DATA: level = "data"; break; + case L_VERIFY_DISK_TO_CATALOG: + level="disk_to_catalog"; + break; default: Jmsg1(jcr, M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->JobLevel); goto bail_out; @@ -298,6 +321,11 @@ int do_verify(JCR *jcr) get_attributes_and_compare_to_catalog(jcr, JobId); break; + case L_VERIFY_DISK_TO_CATALOG: + Dmsg0(10, "Verify level=disk_to_catalog\n"); + get_attributes_and_compare_to_catalog(jcr, JobId); + break; + case L_VERIFY_INIT: /* Build catalog */ Dmsg0(10, "Verify level=init\n"); @@ -510,7 +538,8 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId) * Find equivalent record in the database */ fdbr.FileId = 0; - if (!db_get_file_attributes_record(jcr, jcr->db, jcr->fname, &fdbr)) { + if (!db_get_file_attributes_record(jcr, jcr->db, jcr->fname, + jcr->verify_jr, &fdbr)) { Jmsg(jcr, M_INFO, 0, _("New file: %s\n"), jcr->fname); Dmsg1(020, _("File not in catalog: %s\n"), jcr->fname); stat = JS_Differences; diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 1f9662d4ba..689ae4d4d6 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -843,6 +843,8 @@ static int verify_cmd(JCR *jcr) jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG; } else if (strcasecmp(level, "data") == 0){ jcr->JobLevel = L_VERIFY_DATA; + } else if (strcasecmp(level, "disk_to_catalog") == 0) { + jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG; } else { bnet_fsend(dir, "2994 Bad verify level: %s\n", dir->msg); return 0; @@ -875,6 +877,9 @@ static int verify_cmd(JCR *jcr) /* Inform Storage daemon that we are done */ bnet_sig(sd, BNET_TERMINATE); + break; + case L_VERIFY_DISK_TO_CATALOG: + do_verify(jcr); break; default: bnet_fsend(dir, "2994 Bad verify level: %s\n", dir->msg); diff --git a/bacula/src/filed/verify.c b/bacula/src/filed/verify.c index bd5ac212e0..5bbb0db369 100644 --- a/bacula/src/filed/verify.c +++ b/bacula/src/filed/verify.c @@ -192,7 +192,7 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt) return 0; } - /* If file opened, compute MD5 */ + /* If file opened, compute MD5 or SHA1 hash */ if (is_bopen(&bfd) && ff_pkt->flags & FO_MD5) { char MD5buf[40]; /* 24 should do */ MD5Init(&md5c); diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index e3e012b61c..88217eeb26 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -40,6 +40,7 @@ #define L_VERIFY_CATALOG 'C' /* verify from catalog */ #define L_VERIFY_INIT 'V' /* verify save (init DB) */ #define L_VERIFY_VOLUME_TO_CATALOG 'O' /* verify Volume to catalog entries */ +#define L_VERIFY_DISK_TO_CATALOG 'd' /* verify Disk attributes to catalog */ #define L_VERIFY_DATA 'A' /* verify data on volume */ #define L_BASE 'B' /* Base level job */ @@ -154,7 +155,8 @@ struct JCR { POOLMEM *fname; /* name to put into catalog */ int fn_printed; /* printed filename */ POOLMEM *stime; /* start time for incremental/differential */ - JOB_DBR jr; /* Job record in Database */ + JOB_DBR jr; /* Job DB record for current job */ + JOB_DBR *verify_jr; /* Pointer to target job */ uint32_t RestoreJobId; /* Id specified by UA */ POOLMEM *client_uname; /* client uname */ int replace; /* Replace option */ diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 1bf6a8836b..56f311f6be 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -575,7 +575,7 @@ static int record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) } fr.JobId = mjcr->JobId; fr.FileId = 0; - if (db_get_file_attributes_record(bjcr, db, attr->fname, &fr)) { + if (db_get_file_attributes_record(bjcr, db, attr->fname, NULL, &fr)) { if (verbose > 1) { Pmsg1(000, _("File record already exists for: %s\n"), attr->fname); } diff --git a/bacula/src/version.h b/bacula/src/version.h index 225618e808..9a35e2d15a 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -2,8 +2,8 @@ #undef VERSION #define VERSION "1.32b" #define VSTRING "1" -#define BDATE "10 Oct 2003" -#define LSMDATE "10Oct03" +#define BDATE "14 Oct 2003" +#define LSMDATE "14Oct03" /* Debug flags */ #undef DEBUG