]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/backup.c
Fix #2940 Allow specific Director job code in WriteBootstrap directive
[bacula/bacula] / bacula / src / dird / backup.c
index 89109f2b281b61206d7a3303fa002c910c3f4bec..10f301f011a1a49b6f54ab8a1e0baecb93a39746 100644 (file)
@@ -1,20 +1,22 @@
 /*
-   Bacula® - The Network Backup Solution
+   Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2017 Kern Sibbald
 
-   The main author of Bacula is Kern Sibbald, with contributions from many
-   others, a complete list can be found in the file AUTHORS.
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
 
    You may use this file and others of this release according to the
    license defined in the LICENSE file, which includes the Affero General
    Public License, v3.0 ("AGPLv3") and some additional permissions and
    terms pursuant to its AGPLv3 Section 7.
 
-   Bacula® is a registered trademark of Kern Sibbald.
+   This notice must be preserved when any source code is
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
- *
  *   Bacula Director -- backup.c -- responsible for doing backup jobs
  *
  *     Kern Sibbald, March MM
@@ -25,7 +27,6 @@
  *     Open connection with File daemon and pass him commands
  *       to do the backup.
  *     When the File daemon finishes the job, update the DB.
- *
  */
 
 #include "bacula.h"
@@ -39,6 +40,11 @@ static char storaddr[]  = "storage address=%s port=%d ssl=%d\n";
 /* Responses received from File daemon */
 static char OKbackup[]   = "2000 OK backup\n";
 static char OKstore[]    = "2000 OK storage\n";
+/* After 17 Aug 2013 */
+static char newEndJob[]  = "2800 End Job TermCode=%d JobFiles=%u "
+                           "ReadBytes=%llu JobBytes=%llu Errors=%u "
+                           "VSS=%d Encrypt=%d "
+                           "CommBytes=%lld CompressCommBytes=%lld\n";
 /* Pre 17 Aug 2013 */
 static char EndJob[]     = "2800 End Job TermCode=%d JobFiles=%u "
                            "ReadBytes=%llu JobBytes=%llu Errors=%u "
@@ -240,6 +246,7 @@ bool send_accurate_current_files(JCR *jcr)
    db_list_ctx nb;
    char ed1[50];
 
+   /* In base level, no previous job is used and no restart incomplete jobs */
    if (jcr->is_canceled() || jcr->is_JobLevel(L_BASE)) {
       return true;
    }
@@ -255,9 +262,14 @@ bool send_accurate_current_files(JCR *jcr)
       } else if (!jcr->rerunning) {
          return true;
       }
+
+   } else if (jcr->is_JobLevel(L_VERIFY_DATA)) {
+      char ed1[50];
+      jobids.add(edit_uint64(jcr->previous_jr.JobId, ed1));
+
    } else {
       /* For Incr/Diff level, we search for older jobs */
-      db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
+      db_get_accurate_jobids(jcr, jcr->db, &jcr->jr, &jobids);
 
       /* We are in Incr/Diff, but no Full to build the accurate list... */
       if (jobids.count == 0) {
@@ -266,6 +278,7 @@ bool send_accurate_current_files(JCR *jcr)
       }
    }
 
+   /* For incomplete Jobs, we add our own id */
    if (jcr->rerunning) {
       edit_int64(jcr->JobId, ed1);
       jobids.add(ed1);
@@ -305,7 +318,7 @@ bool send_accurate_current_files(JCR *jcr)
       if (!db_get_file_list(jcr, jcr->db_batch,
                        jobids.list, jcr->use_accurate_chksum, false /* no delta */,
                        accurate_list_handler, (void *)jcr)) {
-         Jmsg1(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+         Jmsg1(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db_batch));
          return false;
       }
    }
@@ -355,7 +368,7 @@ bool send_client_addr_to_sd(JCR *jcr)
    /*
     * Send Client address to the SD
     */
-   sd->fsend(clientaddr, jcr->client->address, jcr->client->FDport, tls_need);
+   sd->fsend(clientaddr, jcr->client->address(), jcr->client->FDport, tls_need);
    if (!response(jcr, sd, OKclient, "Client", DISPLAY_ERROR)) {
       return false;
    }
@@ -432,8 +445,13 @@ bool do_backup(JCR *jcr)
    }
 
    /* Print Job Start message */
-   Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"),
+   if (jcr->rerunning) {
+      Jmsg(jcr, M_INFO, 0, _("Restart Incomplete Backup JobId %s, Job=%s\n"),
+           edit_uint64(jcr->JobId, ed1), jcr->Job);
+   } else {
+      Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"),
            edit_uint64(jcr->JobId, ed1), jcr->Job);
+   }
 
    jcr->setJobStatus(JS_Running);
    Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
@@ -442,6 +460,34 @@ bool do_backup(JCR *jcr)
       return false;
    }
 
+   /* For incomplete Jobs, we add our own id */
+   if (jcr->rerunning) {
+      edit_int64(jcr->JobId, ed1);
+      Mmsg(buf, "SELECT max(FileIndex) FROM File WHERE JobId=%s", ed1);
+      if (db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+         Jmsg(jcr, M_INFO, 0, _("Found %ld files from prior incomplete Job.\n"),
+            (int32_t)job.value);
+      } else {
+         Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+         return false;
+      }
+      jcr->JobFiles = job.value;
+      Dmsg1(100, "==== FI=%ld\n", jcr->JobFiles);
+      Mmsg(buf, "SELECT VolSessionId FROM Job WHERE JobId=%s", ed1);
+      if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+         Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+         return false;
+      }
+      jcr->VolSessionId = job.value;
+      Mmsg(buf, "SELECT VolSessionTime FROM Job WHERE JobId=%s", ed1);
+      if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+         Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+         return false;
+      }
+      jcr->VolSessionTime = job.value;
+      Dmsg4(100, "JobId=%s JobFiles=%ld VolSessionId=%ld VolSessionTime=%ld\n", ed1,
+            jcr->JobFiles, jcr->VolSessionId, jcr->VolSessionTime);
+   }
 
    /*
     * Open a message channel connection with the Storage
@@ -507,10 +553,12 @@ bool do_backup(JCR *jcr)
       send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
    }
 
+   send_snapshot_retention(jcr, jcr->snapshot_retention);
+
    store = jcr->wstore;
 
    if (jcr->sd_calls_client) {
-      if (jcr->FDVersion < 5) {
+      if (jcr->FDVersion < 10) {
          Jmsg(jcr, M_FATAL, 0, _("The File daemon does not support SDCallsClient.\n"));
          goto bail_out;
       }
@@ -620,7 +668,9 @@ int wait_for_job_termination(JCR *jcr, int timeout)
    uint32_t JobWarnings = 0;
    uint64_t ReadBytes = 0;
    uint64_t JobBytes = 0;
-   int VSS = 0;
+   uint64_t CommBytes = 0;
+   uint64_t CommCompressedBytes = 0;
+   int VSS = 0;                 /* or Snapshot on Unix */
    int Encrypt = 0;
    btimer_t *tid=NULL;
 
@@ -631,7 +681,10 @@ int wait_for_job_termination(JCR *jcr, int timeout)
       /* Wait for Client to terminate */
       while ((n = bget_dirmsg(fd)) >= 0) {
          if (!fd_ok &&
-              (sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles,
+             (sscanf(fd->msg, newEndJob, &jcr->FDJobStatus, &JobFiles,
+                     &ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt,
+                     &CommBytes, &CommCompressedBytes) == 9 ||
+              sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles,
                      &ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt) == 7 ||
               sscanf(fd->msg, OldEndJob, &jcr->FDJobStatus, &JobFiles,
                      &ReadBytes, &JobBytes, &JobErrors) == 5)) {
@@ -662,7 +715,7 @@ int wait_for_job_termination(JCR *jcr, int timeout)
    }
 
    /*
-    * Force cancel in SD if failing,
+    * Force cancel in SD if failing, but not for Incomplete jobs
     *  so that we let the SD despool.
     */
    Dmsg5(100, "cancel=%d fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", jcr->is_canceled(), fd_ok, jcr->FDJobStatus,
@@ -683,7 +736,9 @@ int wait_for_job_termination(JCR *jcr, int timeout)
       jcr->ReadBytes = ReadBytes;
       jcr->JobBytes = JobBytes;
       jcr->JobWarnings = JobWarnings;
-      jcr->VSS = VSS;
+      jcr->CommBytes = CommBytes;
+      jcr->CommCompressedBytes = CommCompressedBytes;
+      jcr->Snapshot = VSS;
       jcr->Encrypt = Encrypt;
    } else if (jcr->getJobStatus() != JS_Canceled) {
       Jmsg(jcr, M_FATAL, 0, _("No Job status returned from FD.\n"));
@@ -713,10 +768,10 @@ void backup_cleanup(JCR *jcr, int TermCode)
 {
    char sdt[50], edt[50], schedt[50];
    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30];
-   char ec6[30], ec7[30], ec8[30], elapsed[50];
-   char data_compress[200];
-   char term_code[100], fd_term_msg[100], sd_term_msg[100];
-   const char *term_msg;
+   char ec6[30], ec7[30], ec8[30], ec9[30], ec10[30], elapsed[50];
+   char data_compress[200], comm_compress[200];
+   char fd_term_msg[100], sd_term_msg[100];
+   POOL_MEM term_msg;
    int msg_type = M_INFO;
    MEDIA_DBR mr;
    CLIENT_DBR cr;
@@ -725,6 +780,8 @@ void backup_cleanup(JCR *jcr, int TermCode)
    POOL_MEM base_info;
    POOL_MEM vol_info;
 
+   remove_dummy_jobmedia_records(jcr);
+
    if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
       vbackup_cleanup(jcr, TermCode);
       return;
@@ -771,17 +828,21 @@ void backup_cleanup(JCR *jcr, int TermCode)
    switch (jcr->JobStatus) {
       case JS_Terminated:
          if (jcr->JobErrors || jcr->SDErrors) {
-            term_msg = _("Backup OK -- with warnings");
+            Mmsg(term_msg, _("Backup OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
+
          } else {
-            term_msg = _("Backup OK");
+            Mmsg(term_msg, _("Backup OK"));
          }
          break;
+      case JS_Incomplete:
+         Mmsg(term_msg, _("Backup failed -- incomplete"));
+         break;
       case JS_Warnings:
-         term_msg = _("Backup OK -- with warnings");
+         Mmsg(term_msg, _("Backup OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
          break;
       case JS_FatalError:
       case JS_ErrorTerminated:
-         term_msg = _("*** Backup Error ***");
+         Mmsg(term_msg, _("*** Backup Error ***"));
          msg_type = M_ERROR;          /* Generate error message */
          if (jcr->store_bsock) {
             jcr->store_bsock->signal(BNET_TERMINATE);
@@ -791,7 +852,7 @@ void backup_cleanup(JCR *jcr, int TermCode)
          }
          break;
       case JS_Canceled:
-         term_msg = _("Backup Canceled");
+         Mmsg(term_msg, _("Backup Canceled"));
          if (jcr->store_bsock) {
             jcr->store_bsock->signal(BNET_TERMINATE);
             if (jcr->SD_msg_chan_started) {
@@ -800,8 +861,7 @@ void backup_cleanup(JCR *jcr, int TermCode)
          }
          break;
       default:
-         term_msg = term_code;
-         sprintf(term_code, _("Inappropriate term code: %c\n"), jcr->JobStatus);
+         Mmsg(term_msg, _("Inappropriate term code: %c\n"), jcr->JobStatus);
          break;
    }
    bstrftimes(schedt, sizeof(schedt), jcr->jr.SchedTime);
@@ -809,10 +869,9 @@ void backup_cleanup(JCR *jcr, int TermCode)
    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
    RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
    if (RunTime <= 0) {
-      kbps = 0;
-   } else {
-      kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime);
+      RunTime = 1;
    }
+   kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime);
    if (!db_get_job_volume_names(jcr, jcr->db, jcr->jr.JobId, &jcr->VolumeName)) {
       /*
        * Note, if the job has erred, most likely it did not write any
@@ -829,12 +888,12 @@ void backup_cleanup(JCR *jcr, int TermCode)
    if (jcr->ReadBytes == 0) {
       bstrncpy(data_compress, "None", sizeof(data_compress));
    } else {
-      compression = (double)100 - 100.0 * ((double)jcr->JobBytes / (double)jcr->ReadBytes);
+      compression = (double)100 - 100.0 * ((double)jcr->SDJobBytes / (double)jcr->ReadBytes);
       if (compression < 0.5) {
          bstrncpy(data_compress, "None", sizeof(data_compress));
       } else {
-         if (jcr->JobBytes > 0) {
-            ratio = (double)jcr->ReadBytes / (double)jcr->JobBytes;
+         if (jcr->SDJobBytes > 0) {
+            ratio = (double)jcr->ReadBytes / (double)jcr->SDJobBytes;
          } else {
             ratio = 1.0;
          }
@@ -842,6 +901,20 @@ void backup_cleanup(JCR *jcr, int TermCode)
             compression, ratio);
       }
    }
+   if (jcr->CommBytes == 0 || jcr->CommCompressedBytes == 0) {
+      bstrncpy(comm_compress, "None", sizeof(comm_compress));
+   } else {
+      compression = (double)100 - 100.0 * ((double)jcr->CommCompressedBytes / (double)jcr->CommBytes);
+      if (compression < 0.5) {
+         bstrncpy(comm_compress, "None", sizeof(comm_compress));
+      } else {
+         ratio = (double)jcr->CommBytes / (double)jcr->CommCompressedBytes;
+         bsnprintf(comm_compress, sizeof(comm_compress), "%.1f%% %.1f:1",
+            compression, ratio);
+      }
+      Dmsg2(200, "=== CommCompressed=%lld CommBytes=%lld\n",
+         jcr->CommCompressedBytes, jcr->CommBytes);
+   }
    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
 
@@ -852,10 +925,19 @@ void backup_cleanup(JCR *jcr, int TermCode)
            jcr->nb_base_files_used*100.0/jcr->nb_base_files);
    }
    /* Edit string for last volume size */
-   Mmsg(vol_info, _("%s (%sB)"),
+   if (mr.VolABytes != 0) {
+      Mmsg(vol_info, _("meta: %s (%sB) aligned: %s (%sB)"),
+        edit_uint64_with_commas(mr.VolBytes, ec7),
+        edit_uint64_with_suffix(mr.VolBytes, ec8),
+        edit_uint64_with_commas(mr.VolABytes, ec9),
+        edit_uint64_with_suffix(mr.VolABytes, ec10));
+   } else {
+     Mmsg(vol_info, _("%s (%sB)"),
         edit_uint64_with_commas(mr.VolBytes, ec7),
         edit_uint64_with_suffix(mr.VolBytes, ec8));
+   }
 
+// bmicrosleep(15, 0);                /* for debugging SIGHUP */
 
    Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
 "  Build OS:               %s %s %s\n"
@@ -878,8 +960,9 @@ void backup_cleanup(JCR *jcr, int TermCode)
 "  SD Bytes Written:       %s (%sB)\n"
 "  Rate:                   %.1f KB/s\n"
 "  Software Compression:   %s\n"
+"  Comm Line Compression:  %s\n"
 "%s"                                         /* Basefile info */
-"  VSS:                    %s\n"
+"  Snapshot/VSS:           %s\n"
 "  Encryption:             %s\n"
 "  Accurate:               %s\n"
 "  Volume name(s):         %s\n"
@@ -914,8 +997,9 @@ void backup_cleanup(JCR *jcr, int TermCode)
         edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
         kbps,
         data_compress,
+        comm_compress,
         base_info.c_str(),
-        jcr->VSS?_("yes"):_("no"),
+        jcr->Snapshot?_("yes"):_("no"),
         jcr->Encrypt?_("yes"):_("no"),
         jcr->accurate?_("yes"):_("no"),
         jcr->VolumeName,
@@ -926,7 +1010,7 @@ void backup_cleanup(JCR *jcr, int TermCode)
         jcr->SDErrors,
         fd_term_msg,
         sd_term_msg,
-        term_msg);
+        term_msg.c_str());
 
    Dmsg0(100, "Leave backup_cleanup()\n");
 }
@@ -940,7 +1024,8 @@ void update_bootstrap_file(JCR *jcr)
       BPIPE *bpipe = NULL;
       int got_pipe = 0;
       POOLMEM *fname = get_pool_memory(PM_FNAME);
-      fname = edit_job_codes(jcr, fname, jcr->job->WriteBootstrap, "");
+      fname = edit_job_codes(jcr, fname, jcr->job->WriteBootstrap, "",
+                             job_code_callback_director);
 
       VOL_PARAMS *VolParams = NULL;
       int VolCount;
@@ -952,7 +1037,7 @@ void update_bootstrap_file(JCR *jcr)
          fd = bpipe ? bpipe->wfd : NULL;
       } else {
          /* ***FIXME*** handle BASE */
-         fd = fopen(fname, jcr->is_JobLevel(L_FULL)?"w+b":"a+b");
+         fd = bfopen(fname, jcr->is_JobLevel(L_FULL)?"w+b":"a+b");
       }
       if (fd) {
          VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,