]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/restore.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / dird / restore.c
index f92efb0e2da0f0155c33f046ef7ecaa25ce6d4f9..6dfb15ef140cd47dcdfc9b08f2a3a2aa2f357a09 100644 (file)
@@ -1,11 +1,9 @@
 /*
- *
  *   Bacula Director -- restore.c -- responsible for restoring files
  *
  *     Kern Sibbald, November MM
  *
- *    This routine is run as a separate thread.  There may be more
- *    work to be done to make it totally reentrant!!!!
+ *    This routine is run as a separate thread.  
  * 
  * Current implementation is Catalog verification only (i.e. no
  *  verification versus tape).
@@ -21,7 +19,7 @@
  */
 
 /*
-   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+   Copyright (C) 2000-2003 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
@@ -44,8 +42,8 @@
 #include "dird.h"
 
 /* Commands sent to File daemon */
-static char restorecmd[]   = "restore where=%s\n";
-static char storaddr[]     = "storage address=%s port=%d\n";
+static char restorecmd[]   = "restore replace=%c prelinks=%d where=%s\n";
+static char storaddr[]     = "storage address=%s port=%d ssl=0\n";
 static char sessioncmd[]   = "session %s %ld %ld %ld %ld %ld %ld\n";  
 
 /* Responses received from File daemon */
@@ -66,20 +64,18 @@ static void restore_cleanup(JCR *jcr, int status);
  */
 int do_restore(JCR *jcr) 
 {
-   char dt[MAX_TIME_LENGTH];
    BSOCK   *fd;
    JOB_DBR rjr;                      /* restore job record */
 
-
    if (!get_or_create_client_record(jcr)) {
       restore_cleanup(jcr, JS_ErrorTerminated);
       return 0;
    }
 
    memset(&rjr, 0, sizeof(rjr));
-   jcr->jr.Level = 'F';            /* Full restore */
+   jcr->jr.Level = L_FULL;        /* Full restore */
    jcr->jr.StartTime = jcr->start_time;
-   if (!db_update_job_start_record(jcr->db, &jcr->jr)) {
+   if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
       restore_cleanup(jcr, JS_ErrorTerminated);
       return 0;
@@ -89,44 +85,44 @@ int do_restore(JCR *jcr)
 
    Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
 
-   /*
-    * Find Job Record for Files to be restored
-    */
-   if (jcr->RestoreJobId != 0) {
-      rjr.JobId = jcr->RestoreJobId;    /* specified by UA */
-   } else {
-      rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
-   }
-   if (!db_get_job_record(jcr->db, &rjr)) {
-      Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
-        db_strerror(jcr->db));
-      restore_cleanup(jcr, JS_ErrorTerminated);
-      return 0;
-   }
-   Dmsg3(20, "Got JobId=%d VolSessId=%ld, VolSesTime=%ld\n", 
-            rjr.JobId, rjr.VolSessionId, rjr.VolSessionTime);
-   Dmsg4(20, "StartFile=%ld, EndFile=%ld StartBlock=%ld EndBlock=%ld\n", 
-            rjr.StartFile, rjr.EndFile, rjr.StartBlock, rjr.EndBlock);
-
-   /*
-    * Now find the Volumes we will need for the Restore
+   /* 
+    * The following code is kept temporarily for compatibility.
+    * It is the predecessor to the Bootstrap file.
+    *  DEPRECATED
     */
-   jcr->VolumeName[0] = 0;
-   if (!db_get_job_volume_names(jcr->db, rjr.JobId, jcr->VolumeName) ||
-       jcr->VolumeName[0] == 0) {
-      Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"), 
-        rjr.JobId, db_strerror(jcr->db));
-      restore_cleanup(jcr, JS_ErrorTerminated);
-      return 0;
+   if (!jcr->RestoreBootstrap) {
+      /*
+       * Find Job Record for Files to be restored
+       */
+      if (jcr->RestoreJobId != 0) {
+        rjr.JobId = jcr->RestoreJobId;     /* specified by UA */
+      } else {
+        rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
+      }
+      if (!db_get_job_record(jcr, jcr->db, &rjr)) {
+         Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
+           db_strerror(jcr->db));
+        restore_cleanup(jcr, JS_ErrorTerminated);
+        return 0;
+      }
+
+      /*
+       * Now find the Volumes we will need for the Restore
+       */
+      jcr->VolumeName[0] = 0;
+      if (!db_get_job_volume_names(jcr, jcr->db, rjr.JobId, &jcr->VolumeName) ||
+          jcr->VolumeName[0] == 0) {
+         Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"), 
+           rjr.JobId, db_strerror(jcr->db));
+        restore_cleanup(jcr, JS_ErrorTerminated);
+        return 0;
+      }
+      Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
    }
-   Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
       
 
    /* Print Job Start message */
-   bstrftime(dt, sizeof(dt), jcr->start_time);
-   Jmsg(jcr, M_INFO, 0, _("%s Start Restore Job %s Name=%s, Client=%s, FileSet=%s\n"), 
-      dt, jcr->Job, jcr->job->hdr.name, jcr->client->hdr.name, 
-      jcr->fileset->hdr.name);
+   Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
 
    /*
     * Open a message channel connection with the Storage
@@ -135,7 +131,7 @@ int do_restore(JCR *jcr)
     *
     */
    Dmsg0(10, "Open connection with storage daemon\n");
-   jcr->JobStatus = JS_Blocked;
+   set_jcr_job_status(jcr, JS_WaitSD);
    /*
     * Start conversation with Storage daemon  
     */
@@ -162,13 +158,14 @@ int do_restore(JCR *jcr)
    /* 
     * Start conversation with File daemon  
     */
+   set_jcr_job_status(jcr, JS_WaitFD);
    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
       restore_cleanup(jcr, JS_ErrorTerminated);
       return 0;
    }
 
    fd = jcr->file_bsock;
-   jcr->JobStatus = JS_Running;
+   set_jcr_job_status(jcr, JS_Running);
 
    if (!send_include_list(jcr)) {
       restore_cleanup(jcr, JS_ErrorTerminated);
@@ -185,52 +182,78 @@ int do_restore(JCR *jcr)
     *  then wait for File daemon to make connection
     *  with Storage daemon.
     */
-   jcr->JobStatus = JS_Blocked;
    if (jcr->store->SDDport == 0) {
       jcr->store->SDDport = jcr->store->SDport;
    }
    bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
    Dmsg1(6, "dird>filed: %s\n", fd->msg);
-   if (!response(fd, OKstore, "Storage")) {
+   if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
       restore_cleanup(jcr, JS_ErrorTerminated);
       return 0;
    }
-   jcr->JobStatus = JS_Running;
 
-   /*
-    * Pass the VolSessionId, VolSessionTime, Start and
-    * end File and Blocks on the session command.
+   /* 
+    * Send the bootstrap file -- what Volumes/files to restore
     */
-   bnet_fsend(fd, sessioncmd, 
-            jcr->VolumeName,
-            rjr.VolSessionId, rjr.VolSessionTime, 
-            rjr.StartFile, rjr.EndFile, rjr.StartBlock, 
-            rjr.EndBlock);
-   if (!response(fd, OKsession, "Session")) {
+   if (!send_bootstrap_file(jcr)) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+
+   /* 
+    * The following code is deprecated  
+    */
+   if (!jcr->RestoreBootstrap) {
+      /*
+       * Pass the VolSessionId, VolSessionTime, Start and
+       * end File and Blocks on the session command.
+       */
+      bnet_fsend(fd, sessioncmd, 
+               jcr->VolumeName,
+               rjr.VolSessionId, rjr.VolSessionTime, 
+               rjr.StartFile, rjr.EndFile, rjr.StartBlock, 
+               rjr.EndBlock);
+      if (!response(jcr, fd, OKsession, "Session", DISPLAY_ERROR)) {
+        restore_cleanup(jcr, JS_ErrorTerminated);
+        return 0;
+      }
+   }
+
+   if (!send_run_before_and_after_commands(jcr)) {
       restore_cleanup(jcr, JS_ErrorTerminated);
       return 0;
    }
 
    /* Send restore command */
-   if (jcr->RestoreWhere) {
-      bnet_fsend(fd, restorecmd, jcr->RestoreWhere);
+   char replace, *where;
+
+   if (jcr->replace != 0) {
+      replace = jcr->replace;
+   } else if (jcr->job->replace != 0) {
+      replace = jcr->job->replace;
+   } else {
+      replace = REPLACE_ALWAYS;       /* always replace */
+   }
+   if (jcr->where) {
+      where = jcr->where;            /* override */
+   } else if (jcr->job->RestoreWhere) {
+      where = jcr->job->RestoreWhere; /* no override take from job */
    } else {
-      bnet_fsend(fd, restorecmd,                              
-         jcr->job->RestoreWhere==NULL ? "" : jcr->job->RestoreWhere);
+      where = "";                     /* None */
    }
-   if (!response(fd, OKrestore, "Restore")) {
+   jcr->prefix_links = jcr->job->PrefixLinks;
+   bash_spaces(where);
+   bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
+   unbash_spaces(where);
+
+   if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
       restore_cleanup(jcr, JS_ErrorTerminated);
       return 0;
    }
 
    /* Wait for Job Termination */
-   /*** ****FIXME**** get job termination data */
-   Dmsg0(20, "wait for job termination\n");
-   while (bget_msg(fd, 0) >  0) {
-      Dmsg1(0, "dird<filed: %s\n", fd->msg);
-   }
-
-   restore_cleanup(jcr, JS_Terminated);
+   int stat = wait_for_job_termination(jcr);
+   restore_cleanup(jcr, stat);
 
    return 1;
 }
@@ -239,18 +262,86 @@ int do_restore(JCR *jcr)
  * Release resources allocated during restore.
  *
  */
-static void restore_cleanup(JCR *jcr, int status) 
+static void restore_cleanup(JCR *jcr, int TermCode)
 {
-   char dt[MAX_TIME_LENGTH];
+   char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
+   char ec1[30], ec2[30];
+   char term_code[100], fd_term_msg[100], sd_term_msg[100];
+   char *term_msg;
+   int msg_type;
+   double kbps;
 
    Dmsg0(20, "In restore_cleanup\n");
-   jcr->JobStatus = status;
+   set_jcr_job_status(jcr, TermCode);
 
    update_job_end_record(jcr);
 
-   bstrftime(dt, sizeof(dt), jcr->jr.EndTime);
-   Jmsg(jcr, M_INFO, 0, _("%s End Restore Job %s.\n\n"),
-      dt, jcr->Job);
+   msg_type = M_INFO;                /* by default INFO message */
+   switch (TermCode) {
+   case JS_Terminated:
+      term_msg = _("Restore OK");
+      break;
+   case JS_FatalError:
+   case JS_ErrorTerminated:
+      term_msg = _("*** Restore Error ***"); 
+      msg_type = M_ERROR;         /* Generate error message */
+      if (jcr->store_bsock) {
+        bnet_sig(jcr->store_bsock, BNET_TERMINATE);
+        pthread_cancel(jcr->SD_msg_chan);
+      }
+      break;
+   case JS_Canceled:
+      term_msg = _("Restore Canceled");
+      if (jcr->store_bsock) {
+        bnet_sig(jcr->store_bsock, BNET_TERMINATE);
+        pthread_cancel(jcr->SD_msg_chan);
+      }
+      break;
+   default:
+      term_msg = term_code;
+      sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
+      break;
+   }
+   bstrftime(sdt, sizeof(sdt), jcr->jr.StartTime);
+   bstrftime(edt, sizeof(edt), jcr->jr.EndTime);
+   if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
+      kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
+   } else {
+      kbps = 0;
+   }
+   if (kbps < 0.05) {
+      kbps = 0;
+   }
+
+   jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
+   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\
+Client:                 %s\n\
+Start time:             %s\n\
+End time:               %s\n\
+Files Restored:         %s\n\
+Bytes Restored:         %s\n\
+Rate:                   %.1f KB/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->client->hdr.name,
+       sdt,
+       edt,
+       edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec1),
+       edit_uint64_with_commas(jcr->jr.JobBytes, ec2),
+       (float)kbps,
+       jcr->Errors,
+       fd_term_msg,
+       sd_term_msg,
+       term_msg);
 
    Dmsg0(20, "Leaving restore_cleanup\n");
 }