X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=bacula%2Fsrc%2Fdird%2Fverify.c;h=05834e602015b76e2087f9d4abff8c7a9ca9ba21;hb=9f01506e19567ce5c8fae5699016a1d512647f55;hp=de397ab80da4985376913afa7fe440fdfb39ffd6;hpb=9e51cfbf754dac2fda15544fbde9a1d672d4085d;p=bacula%2Fbacula diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index de397ab80d..05834e6020 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -4,12 +4,6 @@ * * Kern Sibbald, October MM * - * This routine is run as a separate thread. There may be more - * work to be done to make it totally reentrant!!!! - * - * Current implementation is Catalog verification only (i.e. no - * verification versus tape). - * * Basic tasks done here: * Open DB * Open connection with File daemon and pass him commands @@ -21,7 +15,7 @@ */ /* - Copyright (C) 2000-2003 Kern Sibbald and John Walker + Copyright (C) 2000-2004 Kern Sibbald and John Walker This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -70,32 +64,54 @@ 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; - JobId_t JobId = 0; + JOB_DBR jr, verify_jr; + JobId_t verify_jobid = 0; + int stat; + memset(&verify_jr, 0, sizeof(verify_jr)); + if (!jcr->verify_jr) { + jcr->verify_jr = &verify_jr; + } if (!get_or_create_client_record(jcr)) { goto bail_out; } 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)) { - Jmsg(jcr, M_FATAL, 0, _( - "Unable to find JobId of previous InitCatalog Job.\n" - "Please run a Verify with Level=InitCatalog before\n" - "running the current Job.\n")); + if (jcr->JobLevel == L_VERIFY_CATALOG || + jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG || + jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) { + memcpy(&jr, &jcr->jr, sizeof(jr)); + if (jcr->job->verify_job && + (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG || + jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG)) { + 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" + "Please run a Verify with Level=InitCatalog before\n" + "running the current Job.\n")); + } else { + Jmsg(jcr, M_FATAL, 0, _( + "Unable to find JobId of previous Job for this client.\n")); + } goto bail_out; } - JobId = jr.JobId; - Dmsg1(20, "Last full id=%d\n", JobId); + verify_jobid = jr.JobId; + Dmsg1(100, "Last full jobid=%d\n", verify_jobid); } jcr->jr.JobId = jcr->JobId; @@ -107,49 +123,65 @@ int do_verify(JCR *jcr) } if (!jcr->fname) { - jcr->fname = (char *) get_pool_memory(PM_FNAME); + 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); - - 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)) { - Jmsg(jcr, M_FATAL, 0, _("Could not get job record. %s"), db_strerror(jcr->db)); + Jmsg(jcr, M_INFO, 0, _("Start Verify JobId=%d Level=%s Job=%s\n"), + jcr->JobId, level_to_str(jcr->JobLevel), jcr->Job); + + /* + * Now get the job record for the previous backup that interests + * us. We use the verify_jobid that we found above. + */ + if (jcr->JobLevel == L_VERIFY_CATALOG || + jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG || + jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) { + verify_jr.JobId = verify_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); + verify_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); } /* - * If we are verifing a Volume, we need the Storage + * If we are verifying a Volume, we need the Storage * daemon, so open a connection, otherwise, just * create a dummy authorization key (passed to * File daemon but not used). */ if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) { - /* - * Now find the Volumes we will need for the Verify - */ - jcr->VolumeName[0] = 0; - if (!db_get_job_volume_names(jcr, jcr->db, jr.JobId, &jcr->VolumeName) || - jcr->VolumeName[0] == 0) { - Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for verify JobId=%d. %s"), - jr.JobId, db_strerror(jcr->db)); + RBSR *bsr = new_bsr(); + UAContext *ua; + 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 = verify_jr.JobFiles; + if (!write_bsr_file(ua, bsr)) { + free_ua_context(ua); + free_bsr(bsr); goto bail_out; } - Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName); + free_ua_context(ua); + free_bsr(bsr); + if (jcr->RestoreBootstrap) { + free(jcr->RestoreBootstrap); + } + POOLMEM *fname = get_pool_memory(PM_MESSAGE); + Mmsg(&fname, "%s/restore.bsr", working_directory); + jcr->RestoreBootstrap = bstrdup(fname); + free_pool_memory(fname); + /* * Start conversation with Storage daemon */ @@ -173,6 +205,12 @@ 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; + } + Dmsg2(100, "ClientId=%u JobLevel=%c\n", verify_jr.ClientId, jcr->JobLevel); + /* * OK, now connect to the File daemon * and ask him for the files. @@ -185,6 +223,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; @@ -200,23 +239,35 @@ int do_verify(JCR *jcr) * as the Storage address if appropriate. */ switch (jcr->JobLevel) { - case L_VERIFY_INIT: - level = "init"; - break; - case L_VERIFY_CATALOG: - level = "catalog"; - break; - case L_VERIFY_VOLUME_TO_CATALOG: - /* - * send Storage daemon address to the File daemon - */ - if (jcr->store->SDDport == 0) { - jcr->store->SDDport = jcr->store->SDport; - } - bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport); - if (!response(fd, OKstore, "Storage", 1)) { - goto bail_out; - } + case L_VERIFY_INIT: + level = "init"; + break; + case L_VERIFY_CATALOG: + level = "catalog"; + break; + case L_VERIFY_VOLUME_TO_CATALOG: + /* + * send Storage daemon address to the File daemon + */ + if (jcr->store->SDDport == 0) { + jcr->store->SDDport = jcr->store->SDport; + } + bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport); + if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { + goto bail_out; + } + + /* + * Send the bootstrap file -- what Volumes/files to restore + */ + if (!send_bootstrap_file(jcr)) { + goto bail_out; + } + + /* + * The following code is deprecated + */ + if (!jcr->RestoreBootstrap) { /* * Pass the VolSessionId, VolSessionTime, Start and * end File and Blocks on the session command. @@ -226,24 +277,33 @@ int do_verify(JCR *jcr) jr.VolSessionId, jr.VolSessionTime, jr.StartFile, jr.EndFile, jr.StartBlock, jr.EndBlock); - if (!response(fd, OKsession, "Session", 1)) { + if (!response(jcr, fd, OKsession, "Session", DISPLAY_ERROR)) { goto bail_out; } - level = "volume"; - break; - case L_VERIFY_DATA: - level = "data"; - break; - default: - Jmsg1(jcr, M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->JobLevel); - goto bail_out; + } + level = "volume"; + break; + case L_VERIFY_DATA: + level = "data"; + break; + case L_VERIFY_DISK_TO_CATALOG: + level="disk_to_catalog"; + break; + default: + Jmsg2(jcr, M_FATAL, 0, _("Unimplemented save level %d(%c)\n"), jcr->JobLevel, + jcr->JobLevel); + goto bail_out; + } + + if (!send_run_before_and_after_commands(jcr)) { + goto bail_out; } /* * Send verify command/level to File daemon */ bnet_fsend(fd, verifycmd, level); - if (!response(fd, OKverify, "Verify", 1)) { + if (!response(jcr, fd, OKverify, "Verify", DISPLAY_ERROR)) { goto bail_out; } @@ -256,27 +316,28 @@ int do_verify(JCR *jcr) switch (jcr->JobLevel) { case L_VERIFY_CATALOG: Dmsg0(10, "Verify level=catalog\n"); - get_attributes_and_compare_to_catalog(jcr, JobId); + jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ + jcr->SDJobStatus = JS_Terminated; + get_attributes_and_compare_to_catalog(jcr, verify_jobid); break; case L_VERIFY_VOLUME_TO_CATALOG: - int stat; Dmsg0(10, "Verify level=volume\n"); - get_attributes_and_compare_to_catalog(jcr, JobId); - stat = jcr->JobStatus; - set_jcr_job_status(jcr, JS_WaitSD); - wait_for_storage_daemon_termination(jcr); - /* If we terminate normally, use SD term code, else, use ours */ - if (stat == JS_Terminated) { - set_jcr_job_status(jcr, jcr->SDJobStatus); - } else { - set_jcr_job_status(jcr, stat); - } + get_attributes_and_compare_to_catalog(jcr, verify_jobid); + break; + + case L_VERIFY_DISK_TO_CATALOG: + Dmsg0(10, "Verify level=disk_to_catalog\n"); + jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ + jcr->SDJobStatus = JS_Terminated; + get_attributes_and_compare_to_catalog(jcr, verify_jobid); break; case L_VERIFY_INIT: /* Build catalog */ Dmsg0(10, "Verify level=init\n"); + jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ + jcr->SDJobStatus = JS_Terminated; get_attributes_and_put_in_catalog(jcr); break; @@ -285,7 +346,8 @@ int do_verify(JCR *jcr) goto bail_out; } - verify_cleanup(jcr, jcr->JobStatus); + stat = wait_for_job_termination(jcr); + verify_cleanup(jcr, stat); return 1; bail_out: @@ -301,12 +363,13 @@ static void verify_cleanup(JCR *jcr, int TermCode) { char sdt[50], edt[50]; char ec1[30]; - char term_code[100]; + char term_code[100], fd_term_msg[100], sd_term_msg[100]; char *term_msg; int msg_type; JobId_t JobId; + char *Name; - Dmsg0(100, "Enter verify_cleanup()\n"); +// Dmsg1(100, "Enter verify_cleanup() TermCod=%d\n", TermCode); JobId = jcr->jr.JobId; set_jcr_job_status(jcr, TermCode); @@ -315,48 +378,96 @@ static void verify_cleanup(JCR *jcr, int TermCode) msg_type = M_INFO; /* by default INFO message */ switch (TermCode) { - case JS_Terminated: - term_msg = _("Verify OK"); - break; - case JS_ErrorTerminated: - term_msg = _("*** Verify Error ***"); - msg_type = M_ERROR; /* Generate error message */ - break; - case JS_Canceled: - term_msg = _("Verify Canceled"); - break; - case JS_Differences: - term_msg = _("Verify Differences"); - break; - default: - term_msg = term_code; - sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode); - break; + case JS_Terminated: + term_msg = _("Verify OK"); + break; + case JS_ErrorTerminated: + term_msg = _("*** Verify Error ***"); + msg_type = M_ERROR; /* Generate error message */ + break; + case JS_Canceled: + term_msg = _("Verify Canceled"); + break; + case JS_Differences: + term_msg = _("Verify Differences"); + break; + default: + term_msg = term_code; + bsnprintf(term_code, sizeof(term_code), + _("Inappropriate term code: %d %c\n"), TermCode, TermCode); + break; } bstrftime(sdt, sizeof(sdt), jcr->jr.StartTime); bstrftime(edt, sizeof(edt), jcr->jr.EndTime); + if (jcr->job->verify_job) { + Name = jcr->job->verify_job->hdr.name; + } else { + Name = ""; + } - Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n\ + jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg)); + if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) { + jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg)); + Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n\ JobId: %d\n\ Job: %s\n\ FileSet: %s\n\ Verify Level: %s\n\ Client: %s\n\ +Verify JobId: %d\n\ +Verify Job: %s\n\ Start time: %s\n\ End time: %s\n\ Files Examined: %s\n\ +Non-fatal FD errors: %d\n\ +FD termination status: %s\n\ +SD termination status: %s\n\ Termination: %s\n\n"), - edt, - jcr->jr.JobId, - jcr->jr.Job, - jcr->fileset->hdr.name, - level_to_str(jcr->JobLevel), - jcr->client->hdr.name, - sdt, - edt, - edit_uint64_with_commas(jcr->JobFiles, ec1), - term_msg); - + edt, + jcr->jr.JobId, + jcr->jr.Job, + jcr->fileset->hdr.name, + level_to_str(jcr->JobLevel), + jcr->client->hdr.name, + jcr->verify_jr->JobId, + Name, + sdt, + edt, + edit_uint64_with_commas(jcr->JobFiles, ec1), + jcr->Errors, + fd_term_msg, + sd_term_msg, + term_msg); + } else { + Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n\ +JobId: %d\n\ +Job: %s\n\ +FileSet: %s\n\ +Verify Level: %s\n\ +Client: %s\n\ +Verify JobId: %d\n\ +Verify Job: %s\n\ +Start time: %s\n\ +End time: %s\n\ +Files Examined: %s\n\ +Non-fatal FD errors: %d\n\ +FD termination status: %s\n\ +Termination: %s\n\n"), + edt, + jcr->jr.JobId, + jcr->jr.Job, + jcr->fileset->hdr.name, + level_to_str(jcr->JobLevel), + jcr->client->hdr.name, + jcr->verify_jr->JobId, + Name, + sdt, + edt, + edit_uint64_with_commas(jcr->JobFiles, ec1), + jcr->Errors, + fd_term_msg, + term_msg); + } Dmsg0(100, "Leave verify_cleanup()\n"); if (jcr->fname) { free_memory(jcr->fname); @@ -396,14 +507,14 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId) * Attributes * Link name ??? */ - while ((n=bget_msg(fd, 0)) >= 0 && !job_canceled(jcr)) { + while ((n=bget_dirmsg(fd)) >= 0 && !job_canceled(jcr)) { int stream; char *attr, *p, *fn; char Opts_SIG[MAXSTRING]; /* Verify Opts or MD5/SHA1 signature */ fname = check_pool_memory_size(fname, fd->msglen); jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen); - Dmsg1(400, "Atts+SIG=%s\n", fd->msg); + Dmsg1(200, "Atts+SIG=%s\n", fd->msg); if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &stream, fname)) != 3) { Jmsg3(jcr, M_FATAL, 0, _("birdJobFiles++; jcr->FileIndex = file_index; /* remember attribute file_index */ decode_stat(attr, &statf, &LinkFIf); /* decode file stat packet */ do_SIG = NO_SIG; jcr->fn_printed = FALSE; - strcpy(jcr->fname, fname); /* move filename into JCR */ + pm_strcpy(&jcr->fname, fname); /* move filename into JCR */ Dmsg2(040, "dirdfname); Dmsg1(020, "dirddb, 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;