X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Frestore.c;h=27c3abc025b49d74a05ed2910bb7dc69f9bc0dd8;hb=c6e0b63823f177d08c5e7cf8afc677da569bd772;hp=51581b34a65c6cc25a14d919aa5111bc67cac62f;hpb=288ea8ab889d58c06cc1b95aeca0485082a63bb9;p=bacula%2Fbacula diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 51581b34a6..27c3abc025 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -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). @@ -17,10 +15,11 @@ * to do the restore. * Update the DB according to what files where restored???? * + * Version $Id$ */ /* - Copyright (C) 2000, 2001, 2002 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 @@ -43,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 */ @@ -65,36 +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 */ - CLIENT_DBR cr; - /* - * Get or Create a client record - */ - memset(&cr, 0, sizeof(cr)); - strcpy(cr.Name, jcr->client->hdr.name); - cr.AutoPrune = jcr->client->AutoPrune; - cr.FileRetention = jcr->client->FileRetention; - cr.JobRetention = jcr->client->JobRetention; - if (jcr->client_name) { - free(jcr->client_name); - } - jcr->client_name = bstrdup(jcr->client->hdr.name); - if (!db_create_client_record(jcr->db, &cr)) { - Jmsg(jcr, M_ERROR, 0, _("Could not create Client record. %s"), - db_strerror(jcr->db)); + if (!get_or_create_client_record(jcr)) { restore_cleanup(jcr, JS_ErrorTerminated); return 0; } - jcr->jr.ClientId = cr.ClientId; memset(&rjr, 0, sizeof(rjr)); - jcr->jr.Level = 'F'; /* Full restore */ - jcr->jr.StartTime = jcr->start_time; - if (!db_update_job_start_record(jcr->db, &jcr->jr)) { - Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); + jcr->jr.JobLevel = L_FULL; /* Full restore */ + if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { + Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); restore_cleanup(jcr, JS_ErrorTerminated); return 0; } @@ -103,44 +84,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 names 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 @@ -149,7 +130,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 */ @@ -176,13 +157,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); @@ -199,52 +181,79 @@ 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 + */ + if (!send_bootstrap_file(jcr)) { + restore_cleanup(jcr, JS_ErrorTerminated); + return 0; + } + + /* + * The following code is deprecated */ - bnet_fsend(fd, sessioncmd, - jcr->VolumeName, - rjr.VolSessionId, rjr.VolSessionTime, - rjr.StartFile, rjr.EndFile, rjr.StartBlock, - rjr.EndBlock); - if (!response(fd, OKsession, "Session")) { + 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; + char empty = '\0'; + + 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, "dirdmsg); - } - - restore_cleanup(jcr, JS_Terminated); + int stat = wait_for_job_termination(jcr); + restore_cleanup(jcr, stat); return 1; } @@ -253,23 +262,97 @@ 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], ec3[30]; + char term_code[100], fd_term_msg[100], sd_term_msg[100]; + const char *term_msg; + int msg_type; + double kbps; Dmsg0(20, "In restore_cleanup\n"); - if (jcr->jr.EndTime == 0) { - jcr->jr.EndTime = time(NULL); + dequeue_messages(jcr); /* display any queued messages */ + set_jcr_job_status(jcr, TermCode); + + update_job_end_record(jcr); + + msg_type = M_INFO; /* by default INFO message */ + switch (TermCode) { + case JS_Terminated: + if (jcr->ExpectedFiles > jcr->jr.JobFiles) { + term_msg = _("Restore OK -- warning file count mismatch"); + } else { + 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); + if (jcr->SD_msg_chan) { + 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); + if (jcr->SD_msg_chan) { + pthread_cancel(jcr->SD_msg_chan); + } + } + break; + default: + term_msg = term_code; + sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode); + break; + } + bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime); + bstrftimes(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; } - jcr->jr.JobStatus = jcr->JobStatus = status; - if (!db_update_job_end_record(jcr->db, &jcr->jr)) { - Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"), - db_strerror(jcr->db)); + if (kbps < 0.05) { + kbps = 0; } - bstrftime(dt, sizeof(dt), jcr->jr.EndTime); - Jmsg(jcr, M_INFO, 0, _("%s End Restore Job %s.\n"), - dt, jcr->Job); + 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 Expected: %s\n\ + Files Restored: %s\n\ + Bytes Restored: %s\n\ + Rate: %.1f KB/s\n\ + 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->ExpectedFiles, ec1), + edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2), + edit_uint64_with_commas(jcr->jr.JobBytes, ec3), + (float)kbps, + jcr->Errors, + fd_term_msg, + sd_term_msg, + term_msg); Dmsg0(20, "Leaving restore_cleanup\n"); }