]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/vbackup.c
Ignore unknown dot commands in restore tree code
[bacula/bacula] / bacula / src / dird / vbackup.c
index d0e4056d98addf9b1728b9ddd0abbb95da0c6c36..228fb2fb22292eff58bb77b640737c51c7473664 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2008-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2008-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.
    This program is Free Software; you can redistribute it and/or
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
@@ -50,9 +50,7 @@
 
 static const int dbglevel = 10;
 
 
 static const int dbglevel = 10;
 
-static char OKbootstrap[] = "3000 OK bootstrap\n";
-
-static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids);
+static bool create_bootstrap_file(JCR *jcr, char *jobids);
 void vbackup_cleanup(JCR *jcr, int TermCode);
 
 /* 
 void vbackup_cleanup(JCR *jcr, int TermCode);
 
 /* 
@@ -61,12 +59,7 @@ void vbackup_cleanup(JCR *jcr, int TermCode);
  */
 bool do_vbackup_init(JCR *jcr)
 {
  */
 bool do_vbackup_init(JCR *jcr)
 {
-   /* ***FIXME*** remove when implemented in job.c */
-   if (!jcr->rpool_source) {
-      jcr->rpool_source = get_pool_memory(PM_MESSAGE);
-      pm_strcpy(jcr->rpool_source, _("unknown source"));
-   }
-   
+
    if (!get_or_create_fileset_record(jcr)) {
       Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
       return false;
    if (!get_or_create_fileset_record(jcr)) {
       Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
       return false;
@@ -78,6 +71,12 @@ bool do_vbackup_init(JCR *jcr)
       return false;
    }
 
       return false;
    }
 
+   jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
+   if (jcr->jr.PoolId == 0) {
+      Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId);
+      Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
+      return false;
+   }
    /*
     * Note, at this point, pool is the pool for this job.  We
     *  transfer it to rpool (read pool), and a bit later,
    /*
     * Note, at this point, pool is the pool for this job.  We
     *  transfer it to rpool (read pool), and a bit later,
@@ -87,24 +86,18 @@ bool do_vbackup_init(JCR *jcr)
    jcr->rpool = jcr->pool;            /* save read pool */
    pm_strcpy(jcr->rpool_source, jcr->pool_source);
 
    jcr->rpool = jcr->pool;            /* save read pool */
    pm_strcpy(jcr->rpool_source, jcr->pool_source);
 
+   /* If pool storage specified, use it for restore */
+   copy_rstorage(jcr, jcr->pool->storage, _("Pool resource"));
 
    Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
 
 
    Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
 
-   POOLMEM *jobids = get_pool_memory(PM_FNAME);
-   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
-   Dmsg1(000, "Accurate jobids=%s\n", jobids);
-   if (*jobids == 0) {
-      free_pool_memory(jobids);
-      Jmsg(jcr, M_FATAL, 0, _("Cannot find previous JobIds.\n"));
-      return false;
+   jcr->start_time = time(NULL);
+   jcr->jr.StartTime = jcr->start_time;
+   jcr->jr.JobLevel = L_FULL;      /* we want this to appear as a Full backup */
+   if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
    }
 
    }
 
-   if (!create_bootstrap_file(jcr, jobids)) {
-      Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
-      free_pool_memory(jobids);
-      return false;
-   }
-   free_pool_memory(jobids);
 
    /*
     * If the original backup pool has a NextPool, make sure a 
 
    /*
     * If the original backup pool has a NextPool, make sure a 
@@ -117,21 +110,22 @@ bool do_vbackup_init(JCR *jcr)
          return false;
       }
    }
          return false;
       }
    }
-   /* ***FIXME*** this is probably not needed */
    if (!set_migration_wstorage(jcr, jcr->pool)) {
       return false;
    }
    if (!set_migration_wstorage(jcr, jcr->pool)) {
       return false;
    }
+   jcr->pool = jcr->pool->NextPool;
    pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
 
    Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
 
    pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
 
    Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
 
-   create_clones(jcr);
+// create_clones(jcr);
 
    return true;
 }
 
 /*
 
    return true;
 }
 
 /*
- * Do a backup of the specified FileSet
+ * Do a virtual backup, which consolidates all previous backups into
+ *  a sort of synthetic Full.
  *
  *  Returns:  false on failure
  *            true  on success
  *
  *  Returns:  false on failure
  *            true  on success
@@ -140,10 +134,57 @@ bool do_vbackup(JCR *jcr)
 {
    char ed1[100];
    BSOCK *sd;
 {
    char ed1[100];
    BSOCK *sd;
+   char *p;
+   db_list_ctx jobids;
+
+   Dmsg2(100, "rstorage=%p wstorage=%p\n", jcr->rstorage, jcr->wstorage);
+   Dmsg2(100, "Read store=%s, write store=%s\n", 
+      ((STORE *)jcr->rstorage->first())->name(),
+      ((STORE *)jcr->wstorage->first())->name());
 
    /* Print Job Start message */
 
    /* Print Job Start message */
-   Jmsg(jcr, M_INFO, 0, _("Start Vbackup JobId %s, Job=%s\n"),
+   Jmsg(jcr, M_INFO, 0, _("Start Virtual Backup JobId %s, Job=%s\n"),
         edit_uint64(jcr->JobId, ed1), jcr->Job);
         edit_uint64(jcr->JobId, ed1), jcr->Job);
+   if (!jcr->accurate) {
+      Jmsg(jcr, M_WARNING, 0, 
+_("This Job is not an Accurate backup so is not equivalent to a Full backup.\n"));
+   }
+
+   jcr->jr.JobLevel = L_VIRTUAL_FULL;
+   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
+   Dmsg1(10, "Accurate jobids=%s\n", jobids.list);
+   if (jobids.count == 0) {
+      Jmsg(jcr, M_FATAL, 0, _("No previous Jobs found.\n"));
+      return false;
+   }
+
+   jcr->jr.JobLevel = L_FULL;
+
+   /*
+    * Now we find the last job that ran and store it's info in
+    *  the previous_jr record.  We will set our times to the
+    *  values from that job so that anything changed after that
+    *  time will be picked up on the next backup.
+    */
+   p = strrchr(jobids.list, ',');           /* find last jobid */
+   if (p != NULL) {
+      p++;
+   } else {
+      p = jobids.list;
+   }
+   memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr));
+   jcr->previous_jr.JobId = str_to_int64(p);
+   Dmsg1(10, "Previous JobId=%s\n", p);
+   if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
+      Jmsg(jcr, M_FATAL, 0, _("Error getting Job record for previous Job: ERR=%s"),
+               db_strerror(jcr->db));
+      return false;
+   }
+
+   if (!create_bootstrap_file(jcr, jobids.list)) {
+      Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
+      return false;
+   }
 
    /*
     * Open a message channel connection with the Storage
 
    /*
     * Open a message channel connection with the Storage
@@ -160,28 +201,14 @@ bool do_vbackup(JCR *jcr)
       return false;
    }
    sd = jcr->store_bsock;
       return false;
    }
    sd = jcr->store_bsock;
+
    /*
     * Now start a job with the Storage daemon
     */
    /*
     * Now start a job with the Storage daemon
     */
-   Dmsg2(000, "Read store=%s, write store=%s\n", 
-      ((STORE *)jcr->rstorage->first())->name(),
-      ((STORE *)jcr->wstorage->first())->name());
-   if (((STORE *)jcr->rstorage->first())->name() == ((STORE *)jcr->wstorage->first())->name()) {
-      Jmsg(jcr, M_FATAL, 0, _("Read storage \"%s\" same as write storage.\n"),
-           ((STORE *)jcr->rstorage->first())->name());
+   if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage, /*send_bsr*/true)) {
       return false;
    }
       return false;
    }
-   if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage)) {
-      return false;
-   }
-   Dmsg0(000, "Storage daemon connection OK\n");
-
-   if (!send_bootstrap_file(jcr, sd) ||
-       !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
-      return false;
-   }
-
-   Dmsg0(000, "Bootstrap file sent\n");
+   Dmsg0(100, "Storage daemon connection OK\n");
 
    /*    
     * We re-update the job start record so that the start
 
    /*    
     * We re-update the job start record so that the start
@@ -198,7 +225,7 @@ bool do_vbackup(JCR *jcr)
    jcr->jr.JobTDate = jcr->start_time;
    set_jcr_job_status(jcr, JS_Running);
 
    jcr->jr.JobTDate = jcr->start_time;
    set_jcr_job_status(jcr, JS_Running);
 
-   /* Update job start record for this migration control job */
+   /* Update job start record */
    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
       return false;
    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
       return false;
@@ -220,11 +247,10 @@ bool do_vbackup(JCR *jcr)
       return false;
    }
 
       return false;
    }
 
-
    set_jcr_job_status(jcr, JS_Running);
 
    /* Pickup Job termination data */
    set_jcr_job_status(jcr, JS_Running);
 
    /* Pickup Job termination data */
-   /* 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);
    set_jcr_job_status(jcr, jcr->SDJobStatus);
    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
    wait_for_storage_daemon_termination(jcr);
    set_jcr_job_status(jcr, jcr->SDJobStatus);
    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
@@ -243,22 +269,36 @@ bool do_vbackup(JCR *jcr)
 void vbackup_cleanup(JCR *jcr, int TermCode)
 {
    char sdt[50], edt[50], schedt[50];
 void vbackup_cleanup(JCR *jcr, int TermCode)
 {
    char sdt[50], edt[50], schedt[50];
-   char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], compress[50];
-   char ec6[30], ec7[30], ec8[30], elapsed[50];
-   char term_code[100], fd_term_msg[100], sd_term_msg[100];
+   char ec1[30], ec3[30], ec4[30], compress[50];
+   char ec7[30], ec8[30], elapsed[50];
+   char term_code[100], sd_term_msg[100];
    const char *term_msg;
    int msg_type = M_INFO;
    MEDIA_DBR mr;
    CLIENT_DBR cr;
    double kbps, compression;
    utime_t RunTime;
    const char *term_msg;
    int msg_type = M_INFO;
    MEDIA_DBR mr;
    CLIENT_DBR cr;
    double kbps, compression;
    utime_t RunTime;
+   POOL_MEM query(PM_MESSAGE);
 
    Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
    memset(&mr, 0, sizeof(mr));
    memset(&cr, 0, sizeof(cr));
 
 
    Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
    memset(&mr, 0, sizeof(mr));
    memset(&cr, 0, sizeof(cr));
 
+   jcr->set_JobLevel(L_FULL);         /* we want this to appear as a Full backup */
+   jcr->jr.JobLevel = L_FULL;         /* we want this to appear as a Full backup */
+   jcr->JobFiles = jcr->SDJobFiles;
+   jcr->JobBytes = jcr->SDJobBytes;
    update_job_end(jcr, TermCode);
 
    update_job_end(jcr, TermCode);
 
+   /* 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(jcr->JobId, ec3));
+   db_sql_query(jcr->db, query.c_str(), NULL, NULL);
+
+   /* Get the fully updated job record */
    if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
          db_strerror(jcr->db));
    if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
          db_strerror(jcr->db));
@@ -282,7 +322,7 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
 
    switch (jcr->JobStatus) {
       case JS_Terminated:
 
    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");
             term_msg = _("Backup OK -- with warnings");
          } else {
             term_msg = _("Backup OK");
@@ -345,16 +385,13 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
          bsnprintf(compress, sizeof(compress), "%.1f %%", compression);
       }
    }
          bsnprintf(compress, sizeof(compress), "%.1f %%", compression);
       }
    }
-   jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
 
    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
 
-// 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"
 "  Build OS:               %s %s %s\n"
 "  JobId:                  %d\n"
 "  Job:                    %s\n"
-"  Backup Level:           %s%s\n"
+"  Backup Level:           Virtual Full\n"
 "  Client:                 \"%s\" %s\n"
 "  FileSet:                \"%s\" %s\n"
 "  Pool:                   \"%s\" (From %s)\n"
 "  Client:                 \"%s\" %s\n"
 "  FileSet:                \"%s\" %s\n"
 "  Pool:                   \"%s\" (From %s)\n"
@@ -365,29 +402,20 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
 "  End time:               %s\n"
 "  Elapsed time:           %s\n"
 "  Priority:               %d\n"
 "  End time:               %s\n"
 "  Elapsed time:           %s\n"
 "  Priority:               %d\n"
-"  FD Files Written:       %s\n"
 "  SD Files Written:       %s\n"
 "  SD Files Written:       %s\n"
-"  FD Bytes Written:       %s (%sB)\n"
 "  SD Bytes Written:       %s (%sB)\n"
 "  Rate:                   %.1f KB/s\n"
 "  SD Bytes Written:       %s (%sB)\n"
 "  Rate:                   %.1f KB/s\n"
-"  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"
 "  Last Volume Bytes:      %s (%sB)\n"
 "  Volume name(s):         %s\n"
 "  Volume Session Id:      %d\n"
 "  Volume Session Time:    %d\n"
 "  Last Volume Bytes:      %s (%sB)\n"
-"  Non-fatal FD errors:    %d\n"
 "  SD Errors:              %d\n"
 "  SD Errors:              %d\n"
-"  FD termination status:  %s\n"
 "  SD termination status:  %s\n"
 "  Termination:            %s\n\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,
         HOST_OS, DISTNAME, DISTVER,
         jcr->jr.JobId,
         jcr->jr.Job,
-        level_to_str(jcr->JobLevel), jcr->since,
         jcr->client->name(), cr.Uname,
         jcr->fileset->name(), jcr->FSCreateTime,
         jcr->pool->name(), jcr->pool_source,
         jcr->client->name(), cr.Uname,
         jcr->fileset->name(), jcr->FSCreateTime,
         jcr->pool->name(), jcr->pool_source,
@@ -399,24 +427,15 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
         edit_utime(RunTime, elapsed, sizeof(elapsed)),
         jcr->JobPriority,
         edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
         edit_utime(RunTime, elapsed, sizeof(elapsed)),
         jcr->JobPriority,
         edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
-        edit_uint64_with_commas(jcr->SDJobFiles, ec2),
         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
         edit_uint64_with_suffix(jcr->jr.JobBytes, ec4),
         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
         edit_uint64_with_suffix(jcr->jr.JobBytes, ec4),
-        edit_uint64_with_commas(jcr->SDJobBytes, ec5),
-        edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
         kbps,
         kbps,
-        compress,
-        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->VolumeName,
         jcr->VolSessionId,
         jcr->VolSessionTime,
         edit_uint64_with_commas(mr.VolBytes, ec7),
         edit_uint64_with_suffix(mr.VolBytes, ec8),
-        jcr->Errors,
         jcr->SDErrors,
         jcr->SDErrors,
-        fd_term_msg,
         sd_term_msg,
         term_msg);
 
         sd_term_msg,
         term_msg);
 
@@ -447,7 +466,7 @@ int insert_bootstrap_handler(void *ctx, int num_fields, char **row)
 }
 
 
 }
 
 
-static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids)
+static bool create_bootstrap_file(JCR *jcr, char *jobids)
 {
    RESTORE_CTX rx;
    UAContext *ua;
 {
    RESTORE_CTX rx;
    UAContext *ua;
@@ -477,7 +496,7 @@ static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids)
        * Find files for this JobId and insert them in the tree
        */
       Mmsg(rx.query, uar_sel_files, edit_int64(JobId, ed1));
        * Find files for this JobId and insert them in the tree
        */
       Mmsg(rx.query, uar_sel_files, edit_int64(JobId, ed1));
-      Dmsg1(000, "uar_sel_files=%s\n", rx.query);
+      Dmsg1(100, "uar_sel_files=%s\n", rx.query);
       if (!db_sql_query(ua->db, rx.query, insert_bootstrap_handler, (void *)rx.bsr)) {
          Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(ua->db));
       }
       if (!db_sql_query(ua->db, rx.query, insert_bootstrap_handler, (void *)rx.bsr)) {
          Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(ua->db));
       }
@@ -487,11 +506,10 @@ static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids)
 #endif
 
    complete_bsr(ua, rx.bsr);
 #endif
 
    complete_bsr(ua, rx.bsr);
-// Dmsg0(000, "Print bsr\n");
-// print_bsr(ua, rx.bsr);
-
    jcr->ExpectedFiles = write_bsr_file(ua, rx);
    jcr->ExpectedFiles = write_bsr_file(ua, rx);
-   Dmsg1(000, "Found %d files to consolidate.\n", jcr->ExpectedFiles);
+   if (debug_level >= 10) {
+      Dmsg1(000,  "Found %d files to consolidate.\n", jcr->ExpectedFiles);
+   }
    if (jcr->ExpectedFiles == 0) {
       free_ua_context(ua);
       free_bsr(rx.bsr);
    if (jcr->ExpectedFiles == 0) {
       free_ua_context(ua);
       free_bsr(rx.bsr);