X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fbackup.c;h=029dfa0c89179ab8bb34bb8068062310be01394b;hb=a88224a3ce120783d72e770ff9a04fcac635333a;hp=6d7c43d172814442f2288cce6b4974aa3b46f043;hpb=50214f14890aeacf111813aa2749005efdb1ff9a;p=bacula%2Fbacula diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 6d7c43d172..029dfa0c89 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2008 Free Software Foundation Europe e.V. + Copyright (C) 2000-2009 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. @@ -65,6 +65,9 @@ static char OldEndJob[] = "2800 End Job TermCode=%d JobFiles=%u " bool do_backup_init(JCR *jcr) { + if (jcr->get_JobLevel() == L_VIRTUAL_FULL) { + return do_vbackup_init(jcr); + } free_rstorage(jcr); /* we don't read so release */ if (!get_or_create_fileset_record(jcr)) { @@ -78,6 +81,10 @@ bool do_backup_init(JCR *jcr) apply_pool_overrides(jcr); + if (!allow_duplicate_job(jcr)) { + return false; + } + jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name()); if (jcr->jr.PoolId == 0) { return false; @@ -96,6 +103,75 @@ bool do_backup_init(JCR *jcr) return true; } +/* + * Foreach files in currrent list, send "/path/fname\0LStat" to FD + */ +static int accurate_list_handler(void *ctx, int num_fields, char **row) +{ + JCR *jcr = (JCR *)ctx; + + if (job_canceled(jcr)) { + return 1; + } + + if (row[2] > 0) { /* discard when file_index == 0 */ + jcr->file_bsock->fsend("%s%s%c%s", row[0], row[1], 0, row[4]); + } + return 0; +} + +/* + * Send current file list to FD + * DIR -> FD : accurate files=xxxx + * DIR -> FD : /path/to/file\0Lstat + * DIR -> FD : /path/to/dir/\0Lstat + * ... + * DIR -> FD : EOD + */ +bool send_accurate_current_files(JCR *jcr) +{ + POOL_MEM buf; + + if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) { + return true; + } + POOLMEM *jobids = get_pool_memory(PM_FNAME); + + db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids); + + if (*jobids == 0) { + free_pool_memory(jobids); + Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n")); + return false; + } + if (jcr->JobId) { /* display the message only for real jobs */ + Jmsg(jcr, M_INFO, 0, _("Sending Accurate information.\n")); + } + /* to be able to allocate the right size for htable */ + POOLMEM *nb = get_pool_memory(PM_FNAME); + *nb = 0; /* clear buffer */ + Mmsg(buf, "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)",jobids); + db_sql_query(jcr->db, buf.c_str(), db_get_int_handler, nb); + Dmsg2(200, "jobids=%s nb=%s\n", jobids, nb); + jcr->file_bsock->fsend("accurate files=%s\n", nb); + + if (!db_open_batch_connexion(jcr, jcr->db)) { + Jmsg0(jcr, M_FATAL, 0, "Can't get dedicate sql connexion"); + return false; + } + + db_get_file_list(jcr, jcr->db_batch, jobids, accurate_list_handler, (void *)jcr); + + /* TODO: close the batch connexion ? (can be used very soon) */ + + free_pool_memory(jobids); + free_pool_memory(nb); + + jcr->file_bsock->signal(BNET_EOD); + + return true; +} + /* * Do a backup of the specified FileSet * @@ -110,6 +186,9 @@ bool do_backup(JCR *jcr) STORE *store; char ed1[100]; + if (jcr->get_JobLevel() == L_VIRTUAL_FULL) { + return do_vbackup(jcr); + } /* Print Job Start message */ Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"), @@ -225,6 +304,14 @@ bool do_backup(JCR *jcr) Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); } + /* + * If backup is in accurate mode, we send the list of + * all files to FD. + */ + if (!send_accurate_current_files(jcr)) { + goto bail_out; + } + /* Send backup command */ fd->fsend(backupcmd); if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) { @@ -262,7 +349,8 @@ int wait_for_job_termination(JCR *jcr, int timeout) int32_t n = 0; BSOCK *fd = jcr->file_bsock; bool fd_ok = false; - uint32_t JobFiles, Errors; + uint32_t JobFiles, JobErrors; + uint32_t JobWarnings = 0; uint64_t ReadBytes = 0; uint64_t JobBytes = 0; int VSS = 0; @@ -273,15 +361,15 @@ int wait_for_job_termination(JCR *jcr, int timeout) if (fd) { if (timeout) { - tid = start_bsock_timer(fd, timeout); /* TODO: use user timeout */ + tid = start_bsock_timer(fd, timeout); /* TODO: New timeout directive??? */ } /* Wait for Client to terminate */ while ((n = bget_dirmsg(fd)) >= 0) { if (!fd_ok && (sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles, - &ReadBytes, &JobBytes, &Errors, &VSS, &Encrypt) == 7 || + &ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt) == 7 || sscanf(fd->msg, OldEndJob, &jcr->FDJobStatus, &JobFiles, - &ReadBytes, &JobBytes, &Errors) == 5)) { + &ReadBytes, &JobBytes, &JobErrors) == 5)) { fd_ok = true; set_jcr_job_status(jcr, jcr->FDJobStatus); Dmsg1(100, "FDStatus=%c\n", (char)jcr->JobStatus); @@ -299,7 +387,7 @@ int wait_for_job_termination(JCR *jcr, int timeout) if (is_bnet_error(fd)) { Jmsg(jcr, M_FATAL, 0, _("Network error with FD during %s: ERR=%s\n"), - job_type_to_str(jcr->JobType), fd->bstrerror()); + job_type_to_str(jcr->get_JobType()), fd->bstrerror()); } fd->signal(BNET_TERMINATE); /* tell Client we are terminating */ } @@ -309,15 +397,16 @@ int wait_for_job_termination(JCR *jcr, int timeout) cancel_storage_daemon_job(jcr); } - /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/Errors */ + /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */ wait_for_storage_daemon_termination(jcr); /* Return values from FD */ if (fd_ok) { jcr->JobFiles = JobFiles; - jcr->Errors = Errors; + jcr->JobErrors += JobErrors; /* Keep total errors */ jcr->ReadBytes = ReadBytes; jcr->JobBytes = JobBytes; + jcr->JobWarnings = JobWarnings; jcr->VSS = VSS; jcr->Encrypt = Encrypt; } else { @@ -356,6 +445,11 @@ void backup_cleanup(JCR *jcr, int TermCode) double kbps, compression; utime_t RunTime; + if (jcr->get_JobLevel() == L_VIRTUAL_FULL) { + vbackup_cleanup(jcr, TermCode); + return; + } + Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode); memset(&mr, 0, sizeof(mr)); memset(&cr, 0, sizeof(cr)); @@ -385,12 +479,15 @@ void backup_cleanup(JCR *jcr, int TermCode) switch (jcr->JobStatus) { case JS_Terminated: - if (jcr->Errors || jcr->SDErrors) { + if (jcr->JobErrors || jcr->SDErrors) { term_msg = _("Backup OK -- with warnings"); } else { term_msg = _("Backup OK"); } break; + case JS_Warnings: + term_msg = _("Backup OK -- with warnings"); + break; case JS_FatalError: case JS_ErrorTerminated: term_msg = _("*** Backup Error ***"); @@ -453,7 +550,7 @@ void backup_cleanup(JCR *jcr, int TermCode) // bmicrosleep(15, 0); /* for debugging SIGHUP */ - Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n" + Jmsg(jcr, msg_type, 0, _("%s %s %s (%s): %s\n" " Build OS: %s %s %s\n" " JobId: %d\n" " Job: %s\n" @@ -461,6 +558,7 @@ void backup_cleanup(JCR *jcr, int TermCode) " Client: \"%s\" %s\n" " FileSet: \"%s\" %s\n" " Pool: \"%s\" (From %s)\n" +" Catalog: \"%s\" (From %s)\n" " Storage: \"%s\" (From %s)\n" " Scheduled time: %s\n" " Start time: %s\n" @@ -475,6 +573,7 @@ void backup_cleanup(JCR *jcr, int TermCode) " Software Compression: %s\n" " VSS: %s\n" " Encryption: %s\n" +" Accurate: %s\n" " Volume name(s): %s\n" " Volume Session Id: %d\n" " Volume Session Time: %d\n" @@ -484,14 +583,15 @@ void backup_cleanup(JCR *jcr, int TermCode) " FD termination status: %s\n" " SD termination status: %s\n" " Termination: %s\n\n"), - my_name, VERSION, LSMDATE, edt, + BACULA, my_name, VERSION, LSMDATE, edt, HOST_OS, DISTNAME, DISTVER, jcr->jr.JobId, jcr->jr.Job, - level_to_str(jcr->JobLevel), jcr->since, + level_to_str(jcr->get_JobLevel()), jcr->since, jcr->client->name(), cr.Uname, jcr->fileset->name(), jcr->FSCreateTime, jcr->pool->name(), jcr->pool_source, + jcr->catalog->name(), jcr->catalog_source, jcr->wstore->name(), jcr->wstore_source, schedt, sdt, @@ -506,14 +606,15 @@ void backup_cleanup(JCR *jcr, int TermCode) edit_uint64_with_suffix(jcr->SDJobBytes, ec6), kbps, compress, - jcr->VSS?"yes":"no", - jcr->Encrypt?"yes":"no", + jcr->VSS?_("yes"):_("no"), + jcr->Encrypt?_("yes"):_("no"), + jcr->accurate?_("yes"):_("no"), jcr->VolumeName, jcr->VolSessionId, jcr->VolSessionTime, edit_uint64_with_commas(mr.VolBytes, ec7), edit_uint64_with_suffix(mr.VolBytes, ec8), - jcr->Errors, + jcr->JobErrors, jcr->SDErrors, fd_term_msg, sd_term_msg, @@ -535,7 +636,7 @@ void update_bootstrap_file(JCR *jcr) VOL_PARAMS *VolParams = NULL; int VolCount; - char edt[50]; + char edt[50], ed1[50], ed2[50]; if (*fname == '|') { got_pipe = 1; @@ -543,7 +644,7 @@ void update_bootstrap_file(JCR *jcr) fd = bpipe ? bpipe->wfd : NULL; } else { /* ***FIXME*** handle BASE */ - fd = fopen(fname, jcr->JobLevel==L_FULL?"w+b":"a+b"); + fd = fopen(fname, jcr->get_JobLevel()==L_FULL?"w+b":"a+b"); } if (fd) { VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId, @@ -559,17 +660,19 @@ void update_bootstrap_file(JCR *jcr) /* Start output with when and who wrote it */ bstrftimes(edt, sizeof(edt), time(NULL)); fprintf(fd, "# %s - %s - %s%s\n", edt, jcr->jr.Job, - level_to_str(jcr->JobLevel), jcr->since); + level_to_str(jcr->get_JobLevel()), jcr->since); for (int i=0; i < VolCount; i++) { /* Write the record */ fprintf(fd, "Volume=\"%s\"\n", VolParams[i].VolumeName); fprintf(fd, "MediaType=\"%s\"\n", VolParams[i].MediaType); + if (VolParams[i].Slot > 0) { + fprintf(fd, "Slot=%d\n", VolParams[i].Slot); + } fprintf(fd, "VolSessionId=%u\n", jcr->VolSessionId); fprintf(fd, "VolSessionTime=%u\n", jcr->VolSessionTime); - fprintf(fd, "VolFile=%u-%u\n", VolParams[i].StartFile, - VolParams[i].EndFile); - fprintf(fd, "VolBlock=%u-%u\n", VolParams[i].StartBlock, - VolParams[i].EndBlock); + fprintf(fd, "VolAddr=%s-%s\n", + edit_uint64(VolParams[i].StartAddr, ed1), + edit_uint64(VolParams[i].EndAddr, ed2)); fprintf(fd, "FileIndex=%d-%d\n", VolParams[i].FirstIndex, VolParams[i].LastIndex); }