2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula Director -- mac.c -- responsible for doing
22 * migration and copy jobs.
24 * Also handles Copy jobs (March MMVIII)
26 * Written by Kern Sibbald, September MMIV
28 * Basic tasks done here:
29 * Open DB and create records for this job.
30 * Open Message Channel with Storage daemon to tell him a job will be starting.
31 * Open connection with Storage daemon and pass him commands
33 * When the Storage daemon finishes the job, update the DB.
41 static const int dbglevel = 10;
42 static char storaddr[] = "storage address=%s port=%d ssl=%d Job=%s Authentication=%s\n";
43 static char OKstore[] = "2000 OK storage\n";
45 /* Imported subroutines */
46 extern int getJob_to_migrate(JCR *jcr);
47 extern bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1,
48 const char *query2, const char *type);
49 extern bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1,
51 extern bool find_jobids_of_pool_uncopied_jobs(JCR *jcr, idpkt *ids);
53 static bool set_mac_next_pool(JCR *jcr, POOL **pool);
56 * Called here before the job is run to do the job
57 * specific setup. Note, one of the important things to
58 * complete in this init code is to make the definitive
59 * choice of input and output storage devices. This is
60 * because immediately after the init, the job is queued
61 * in the jobq.c code, and it checks that all the resources
62 * (storage resources in particular) are available, so these
63 * must all be properly defined.
65 * previous_jr refers to the job DB record of the Job that is
66 * going to be migrated.
67 * prev_job refers to the job resource of the Job that is
68 * going to be migrated.
69 * jcr is the jcr for the current "migration" job. It is a
70 * control job that is put in the DB as a migration job, which
71 * means that this job migrated a previous job to a new job.
72 * No Volume or File data is associated with this control
74 * wjcr refers to the migrate/copy job that is writing and is run by
75 * the current jcr. It is a backup job that writes the
76 * data written for the previous_jr into the new pool. This
77 * job (wjcr) becomes the new backup job that replaces
78 * the original backup job. Note, this jcr is not really run. It
79 * is simply attached to the current jcr. It will show up in
80 * the Director's status output, but not in the SD or FD, both of
81 * which deal only with the current migration job (i.e. jcr).
83 bool do_mac_init(JCR *jcr)
87 JCR *wjcr; /* jcr of writing job */
91 apply_pool_overrides(jcr);
93 if (!allow_duplicate_job(jcr)) {
97 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
98 if (jcr->jr.PoolId == 0) {
99 Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId);
100 Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
104 * Note, at this point, pool is the pool for this job. We
105 * transfer it to rpool (read pool), and a bit later,
106 * pool will be changed to point to the write pool,
107 * which comes from pool->NextPool.
109 jcr->rpool = jcr->pool; /* save read pool */
110 pm_strcpy(jcr->rpool_source, jcr->pool_source);
111 Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
113 if (!get_or_create_fileset_record(jcr)) {
114 Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
115 Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
119 /* If we find a job or jobs to migrate it is previous_jr.JobId */
120 count = getJob_to_migrate(jcr);
125 set_mac_next_pool(jcr, &pool);
126 return true; /* no work */
129 Dmsg1(dbglevel, "Back from getJob_to_migrate JobId=%d\n", (int)jcr->JobId);
131 if (jcr->previous_jr.JobId == 0) {
132 Dmsg1(dbglevel, "JobId=%d no previous JobId\n", (int)jcr->JobId);
133 Jmsg(jcr, M_INFO, 0, _("No previous Job found to %s.\n"), jcr->get_ActionName(0));
134 set_mac_next_pool(jcr, &pool);
135 return true; /* no work */
138 if (create_restore_bootstrap_file(jcr) < 0) {
139 Jmsg(jcr, M_FATAL, 0, _("Create bootstrap file failed.\n"));
143 if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) {
144 jcr->setJobStatus(JS_Terminated);
145 Dmsg1(dbglevel, "JobId=%d expected files == 0\n", (int)jcr->JobId);
146 if (jcr->previous_jr.JobId == 0) {
147 Jmsg(jcr, M_INFO, 0, _("No previous Job found to %s.\n"), jcr->get_ActionName(0));
149 Jmsg(jcr, M_INFO, 0, _("Previous Job has no data to %s.\n"), jcr->get_ActionName(0));
151 set_mac_next_pool(jcr, &pool);
152 return true; /* no work */
156 Dmsg5(dbglevel, "JobId=%d: Current: Name=%s JobId=%d Type=%c Level=%c\n",
158 jcr->jr.Name, (int)jcr->jr.JobId,
159 jcr->jr.JobType, jcr->jr.JobLevel);
162 job = (JOB *)GetResWithName(R_JOB, jcr->jr.Name);
163 prev_job = (JOB *)GetResWithName(R_JOB, jcr->previous_jr.Name);
166 Jmsg(jcr, M_FATAL, 0, _("Job resource not found for \"%s\".\n"), jcr->jr.Name);
170 Jmsg(jcr, M_FATAL, 0, _("Previous Job resource not found for \"%s\".\n"),
171 jcr->previous_jr.Name);
176 /* Create a write jcr */
177 wjcr = jcr->wjcr = new_jcr(sizeof(JCR), dird_free_jcr);
178 memcpy(&wjcr->previous_jr, &jcr->previous_jr, sizeof(wjcr->previous_jr));
181 * Turn the wjcr into a "real" job that takes on the aspects of
182 * the previous backup job "prev_job".
184 set_jcr_defaults(wjcr, prev_job);
185 /* fix MA 987 cannot copy/migrate jobs with a Level=VF in the job resource
186 * If the prev_job level definition is VirtualFull,
187 * change it to Incremental, otherwise the writing SD would do a VF
189 if (wjcr->getJobLevel() == L_VIRTUAL_FULL) {
190 wjcr->setJobLevel(L_INCREMENTAL);
192 if (!setup_job(wjcr)) {
193 Jmsg(jcr, M_FATAL, 0, _("setup job failed.\n"));
197 /* Now reset the job record from the previous job */
198 memcpy(&wjcr->jr, &jcr->previous_jr, sizeof(wjcr->jr));
199 /* Update the jr to reflect the new values of PoolId and JobId. */
200 wjcr->jr.PoolId = jcr->jr.PoolId;
201 wjcr->jr.JobId = wjcr->JobId;
202 wjcr->sd_client = true;
203 //wjcr->setJobType(jcr->getJobType());
204 wjcr->spool_data = job->spool_data; /* turn on spooling if requested in job */
205 wjcr->spool_size = jcr->spool_size;
208 /* Don't let WatchDog checks Max*Time value on this Job */
209 wjcr->no_maxtime = true;
210 /* Don't check for duplicates on this jobs */
211 wjcr->job->IgnoreDuplicateJobChecking = true;
212 Dmsg4(dbglevel, "wjcr: Name=%s JobId=%d Type=%c Level=%c\n",
213 wjcr->jr.Name, (int)wjcr->jr.JobId,
214 wjcr->jr.JobType, wjcr->jr.JobLevel);
216 if (set_mac_next_pool(jcr, &pool)) {
217 /* If pool storage specified, use it for restore */
218 copy_rstorage(wjcr, pool->storage, _("Pool resource"));
219 copy_rstorage(jcr, pool->storage, _("Pool resource"));
221 wjcr->pool = jcr->pool;
222 wjcr->next_pool = jcr->next_pool;
223 wjcr->jr.PoolId = jcr->jr.PoolId;
230 * set_mac_next_pool() called by do_mac_init()
231 * at differents stages.
232 * The idea here is to make a common subroutine for the
233 * NextPool's search code and to permit do_mac_init()
234 * to return with NextPool set in jcr struct.
236 static bool set_mac_next_pool(JCR *jcr, POOL **retpool)
243 * Get the PoolId used with the original job. Then
244 * find the pool name from the database record.
246 memset(&pr, 0, sizeof(pr));
247 pr.PoolId = jcr->jr.PoolId;
248 if (!db_get_pool_record(jcr, jcr->db, &pr)) {
249 Jmsg(jcr, M_FATAL, 0, _("Pool for JobId %s not in database. ERR=%s\n"),
250 edit_int64(pr.PoolId, ed1), db_strerror(jcr->db));
253 /* Get the pool resource corresponding to the original job */
254 pool = (POOL *)GetResWithName(R_POOL, pr.Name);
257 Jmsg(jcr, M_FATAL, 0, _("Pool resource \"%s\" not found.\n"), pr.Name);
261 if (!apply_wstorage_overrides(jcr, pool)) {
265 Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
271 * Send storage address and authentication to deblock the other
274 static bool send_store_addr_to_sd(JCR *jcr, char *Job, char *sd_auth_key,
275 STORE *store, char *store_address, uint32_t store_port)
277 int tls_need = BNET_TLS_NONE;
279 /* TLS Requirement */
280 if (store->tls_enable) {
281 if (store->tls_require) {
282 tls_need = BNET_TLS_REQUIRED;
284 tls_need = BNET_TLS_OK;
289 * Send Storage address to the SD client
291 Dmsg2(200, "=== Job=%s sd auth key=%s\n", Job, sd_auth_key);
292 jcr->store_bsock->fsend(storaddr, store_address, store_port,
293 tls_need, Job, sd_auth_key);
294 if (!response(jcr, jcr->store_bsock, OKstore, "Storage", DISPLAY_ERROR)) {
295 Dmsg4(050, "Response fail for: JobId=%d storeaddr=%s:%d Job=%s\n",
296 jcr->JobId, store_address, store_port, Job);
297 Jmsg3(jcr, M_FATAL, 0, "Response failure: storeddr=%s:%d Job=%s\n",
298 store_address, store_port, Job);
306 * Do a Migration and Copy of a previous job
308 * Returns: false on failure
311 bool do_mac(JCR *jcr)
315 JCR *wjcr = jcr->wjcr; /* newly migrated job */
322 * If wjcr is NULL, there is nothing to do for this job,
323 * so set a normal status, cleanup and return OK.
326 jcr->setJobStatus(JS_Terminated);
327 mac_cleanup(jcr, JS_Terminated, JS_Terminated);
331 if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
332 Jmsg(jcr, M_FATAL, 0, _("Could not get job record for JobId %s to %s. ERR=%s"),
333 edit_int64(jcr->previous_jr.JobId, ed1),
334 jcr->get_ActionName(0),
335 db_strerror(jcr->db));
336 jcr->setJobStatus(JS_Terminated);
337 mac_cleanup(jcr, JS_Terminated, JS_Terminated);
340 /* Make sure this job was not already migrated */
341 if (jcr->previous_jr.JobType != JT_BACKUP &&
342 jcr->previous_jr.JobType != JT_JOB_COPY) {
343 Jmsg(jcr, M_INFO, 0, _("JobId %s already %s probably by another Job. %s stopped.\n"),
344 edit_int64(jcr->previous_jr.JobId, ed1),
345 jcr->get_ActionName(1),
346 jcr->get_OperationName());
347 jcr->setJobStatus(JS_Terminated);
348 mac_cleanup(jcr, JS_Terminated, JS_Terminated);
352 /* Print Job Start message */
353 Jmsg(jcr, M_INFO, 0, _("Start %s JobId %s, Job=%s\n"),
354 jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
356 Dmsg3(200, "Start %s JobId %s, Job=%s\n",
357 jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
361 * Now separate the read and write storages. jcr has no wstor...
362 * they all go into wjcr.
364 free_rwstorage(wjcr);
366 wjcr->wstore = jcr->wstore;
368 wjcr->wstorage = jcr->wstorage;
369 jcr->wstorage = NULL;
371 /* TODO: See priority with bandwidth parameter */
372 if (jcr->job->max_bandwidth > 0) {
373 jcr->max_bandwidth = jcr->job->max_bandwidth;
374 } else if (jcr->client && jcr->client->max_bandwidth > 0) {
375 jcr->max_bandwidth = jcr->client->max_bandwidth;
378 if (jcr->max_bandwidth > 0) {
379 send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
383 * Open a message channel connection with the Storage
384 * daemon. This is to let him know that our client
385 * will be contacting him for a backup session.
388 jcr->setJobStatus(JS_WaitSD);
389 wjcr->setJobStatus(JS_WaitSD);
392 * Start conversation with write Storage daemon
394 Dmsg0(200, "Connect to write (wjcr) storage daemon.\n");
395 if (!connect_to_storage_daemon(wjcr, 10, SDConnectTimeout, 1)) {
398 wsd = wjcr->store_bsock;
401 * Start conversation with read Storage daemon
403 Dmsg1(200, "Connect to read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
404 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
407 sd = jcr->store_bsock;
409 jcr->sd_calls_client = jcr->client->sd_calls_client;
412 Dmsg2(dbglevel, "Read store=%s, write store=%s\n",
413 ((STORE *)jcr->rstorage->first())->name(),
414 ((STORE *)wjcr->wstorage->first())->name());
417 * Now start a job with the read Storage daemon sending the bsr.
418 * This call returns the sd_auth_key
420 Dmsg1(200, "Start job with read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
421 if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL, /*send_bsr*/true)) {
424 Dmsg0(150, "Read storage daemon connection OK\n");
426 if (jcr->sd_calls_client) {
427 wjcr->sd_calls_client = true;
428 wjcr->sd_client = false;
430 wjcr->sd_calls_client = true;
431 wjcr->sd_client = true;
435 * Now start a job with the write Storage daemon sending.
437 Dmsg1(200, "Start Job with write (wjcr) storage daemon. Jid=%d\n", jcr->JobId);
438 if (!start_storage_daemon_job(wjcr, NULL, wjcr->wstorage, /*no_send_bsr*/false)) {
441 Dmsg0(150, "Write storage daemon connection OK\n");
444 /* Declare the job started to start the MaxRunTime check */
445 jcr->setJobStarted();
448 * We re-update the job start record so that the start
449 * time is set after the run before job. This avoids
450 * that any files created by the run before job will
451 * be saved twice. They will be backed up in the current
452 * job, but not in the next one unless they are changed.
453 * Without this, they will be backed up in this job and
454 * in the next job run because in that case, their date
455 * is after the start of this run.
457 jcr->start_time = time(NULL);
458 jcr->jr.StartTime = jcr->start_time;
459 jcr->jr.JobTDate = jcr->start_time;
460 jcr->setJobStatus(JS_Running);
462 /* Update job start record for this mac control job */
463 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
464 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
468 /* Declare the job started to start the MaxRunTime check */
469 jcr->setJobStarted();
471 wjcr->start_time = time(NULL);
472 wjcr->jr.StartTime = wjcr->start_time;
473 wjcr->jr.JobTDate = wjcr->start_time;
474 wjcr->setJobStatus(JS_Running);
477 /* Update job start record for the real mac backup job */
478 if (!db_update_job_start_record(wjcr, wjcr->db, &wjcr->jr)) {
479 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(wjcr->db));
483 Dmsg4(dbglevel, "wjcr: Name=%s JobId=%d Type=%c Level=%c\n",
484 wjcr->jr.Name, (int)wjcr->jr.JobId,
485 wjcr->jr.JobType, wjcr->jr.JobLevel);
488 if (jcr->sd_calls_client) {
490 * Reading SD must call the "client" i.e. the writing SD
492 if (jcr->SDVersion < 3) {
493 Jmsg(jcr, M_FATAL, 0, _("The Storage daemon does not support SDCallsClient.\n"));
497 /* Setup the storage address and port */
498 store = wjcr->wstore;
499 if (store->SDDport == 0) {
500 store->SDDport = store->SDport;
502 store_address = store->address; /* note: store points to wstore */
504 Dmsg2(200, "Start write message thread jid=%d Job=%s\n", wjcr->JobId, wjcr->Job);
505 if (!run_storage_and_start_message_thread(wjcr, wsd)) {
509 store_port = store->SDDport;
512 * Send writing SD address to the reading SD
514 /* Send and wait for connection */
515 /* ***FIXME*** this should probably be jcr->rstore, store_address, ...
516 * to get TLS right */
517 if (!send_store_addr_to_sd(jcr, wjcr->Job, wjcr->sd_auth_key,
518 store, store_address, store_port)) {
522 /* Start read message thread */
523 Dmsg2(200, "Start read message thread jid=%d Job=%s\n", jcr->JobId, jcr->Job);
524 if (!run_storage_and_start_message_thread(jcr, sd)) {
530 * Writing SD must simulate an FD and call the reading SD
532 * Send Storage daemon address to the writing SD
535 if (store->SDDport == 0) {
536 store->SDDport = store->SDport;
538 store_address = get_storage_address(jcr->client, store);
539 store_port = store->SDDport;
541 /* Start read message thread */
542 Dmsg2(200, "Start read message thread jid=%d Job=%s\n", jcr->JobId, jcr->Job);
543 if (!run_storage_and_start_message_thread(jcr, sd)) {
547 /* Attempt connection for one hour */
548 if (!send_store_addr_to_sd(wjcr, jcr->Job, jcr->sd_auth_key,
549 store, store_address, store_port)) {
552 /* Start write message thread */
553 Dmsg2(200, "Start write message thread jid=%d Job=%s\n", wjcr->JobId, wjcr->Job);
554 if (!run_storage_and_start_message_thread(wjcr, wsd)) {
559 jcr->setJobStatus(JS_Running);
560 wjcr->setJobStatus(JS_Running);
562 /* Pickup Job termination data */
563 /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
564 wait_for_storage_daemon_termination(wjcr);
565 wjcr->setJobStatus(wjcr->SDJobStatus);
566 wait_for_storage_daemon_termination(jcr);
567 jcr->setJobStatus(jcr->SDJobStatus);
568 db_write_batch_file_records(wjcr); /* used by bulk batch file insert */
570 ok = jcr->is_JobStatus(JS_Terminated) && wjcr->is_JobStatus(JS_Terminated);
573 /* Put back jcr write storages for proper cleanup */
574 jcr->wstorage = wjcr->wstorage;
575 jcr->wstore = wjcr->wstore;
577 wjcr->wstorage = NULL;
578 wjcr->file_bsock = NULL;
581 mac_cleanup(jcr, jcr->JobStatus, wjcr->JobStatus);
587 * Called from mac_sql.c for each migration/copy job to start
589 void start_mac_job(JCR *jcr)
591 UAContext *ua = new_ua_context(jcr);
593 char args[MAX_NAME_LENGTH + 50];
596 Mmsg(ua->cmd, "run job=\"%s\" jobid=%s ignoreduplicatecheck=yes pool=\"%s\"",
597 jcr->job->name(), edit_uint64(jcr->MigrateJobId, ed1),
599 if (jcr->next_pool) {
600 bsnprintf(args, sizeof(args), " nextpool=\"%s\"", jcr->next_pool->name());
601 pm_strcat(ua->cmd, args);
603 Dmsg2(dbglevel, "=============== %s cmd=%s\n", jcr->get_OperationName(), ua->cmd);
604 parse_ua_args(ua); /* parse command */
605 JobId_t jobid = run_cmd(ua, ua->cmd);
607 Jmsg(jcr, M_ERROR, 0, _("Could not start migration/copy job.\n"));
609 Jmsg(jcr, M_INFO, 0, _("%s JobId %d started.\n"), jcr->get_OperationName(), (int)jobid);
615 * Release resources allocated during backup.
617 /* ***FIXME*** implement writeTermCode */
618 void mac_cleanup(JCR *jcr, int TermCode, int writeTermCode)
620 char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
621 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], elapsed[50];
622 char ec6[50], ec7[50], ec8[50], ec9[30], ec10[30];
623 char term_code[100], sd_term_msg[100];
624 const char *term_msg;
625 int msg_type = M_INFO;
629 bool goterrors=false;
630 JCR *wjcr = jcr->wjcr;
631 POOL_MEM query(PM_MESSAGE);
634 Dmsg2(100, "Enter mac_cleanup %d %c\n", TermCode, TermCode);
635 update_job_end(jcr, TermCode);
638 * Check if we actually did something.
639 * wjcr is jcr of the newly migrated job.
642 char old_jobid[50], new_jobid[50];
644 edit_uint64(jcr->previous_jr.JobId, old_jobid);
645 edit_uint64(wjcr->jr.JobId, new_jobid);
647 wjcr->JobFiles = jcr->JobFiles = wjcr->SDJobFiles;
648 wjcr->JobBytes = jcr->JobBytes = wjcr->SDJobBytes;
649 wjcr->jr.RealEndTime = 0;
650 wjcr->jr.PriorJobId = jcr->previous_jr.JobId;
652 update_job_end(wjcr, TermCode);
654 /* Update final items to set them to the previous job's values */
655 Mmsg(query, "UPDATE Job SET StartTime='%s',EndTime='%s',"
656 "JobTDate=%s WHERE JobId=%s",
657 jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime,
658 edit_uint64(jcr->previous_jr.JobTDate, ec1),
660 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
662 goterrors = jcr->SDErrors > 0 || jcr->JobErrors > 0 ||
663 jcr->SDJobStatus == JS_Canceled ||
664 jcr->SDJobStatus == JS_ErrorTerminated ||
665 jcr->SDJobStatus == JS_FatalError;
667 if (goterrors && jcr->getJobType() == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
668 Jmsg(jcr, M_WARNING, 0, _("Found errors during the migration process. "
669 "The original job %s will be kept in the catalog "
670 "and the Migration job will be marked in Error\n"), old_jobid);
674 * If we terminated a migration normally:
675 * - mark the previous job as migrated
676 * - move any Log records to the new JobId
677 * - Purge the File records from the previous job
679 if (!goterrors && jcr->getJobType() == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
680 Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
681 (char)JT_MIGRATED_JOB, old_jobid);
682 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
683 UAContext *ua = new_ua_context(jcr);
684 /* Move JobLog to new JobId */
685 Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
686 new_jobid, old_jobid);
687 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
689 /* Move RestoreObjects */
690 Mmsg(query, "UPDATE RestoreObject SET JobId=%s WHERE JobId=%s",
691 new_jobid, old_jobid);
692 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
694 if (jcr->job->PurgeMigrateJob) {
695 /* Purge old Job record */
696 purge_jobs_from_catalog(ua, old_jobid);
698 /* Purge all old file records, but leave Job record */
699 purge_files_from_jobs(ua, old_jobid);
706 * If we terminated a Copy (rather than a Migration) normally:
707 * - copy any Log records to the new JobId
708 * - set type="Job Copy" for the new job
710 if (goterrors || (jcr->getJobType() == JT_COPY && jcr->JobStatus == JS_Terminated)) {
711 /* Copy JobLog to new JobId */
712 Mmsg(query, "INSERT INTO Log (JobId, Time, LogText ) "
713 "SELECT %s, Time, LogText FROM Log WHERE JobId=%s",
714 new_jobid, old_jobid);
715 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
717 /* We are in a real copy job */
718 Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
719 (char)JT_JOB_COPY, new_jobid);
720 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
722 /* Copy RestoreObjects */
723 Mmsg(query, "INSERT INTO RestoreObject (ObjectName,PluginName,RestoreObject,"
724 "ObjectLength,ObjectFullLength,ObjectIndex,ObjectType,"
725 "ObjectCompression,FileIndex,JobId) "
726 "SELECT ObjectName,PluginName,RestoreObject,"
727 "ObjectLength,ObjectFullLength,ObjectIndex,ObjectType,"
728 "ObjectCompression,FileIndex,%s FROM RestoreObject WHERE JobId=%s",
729 new_jobid, old_jobid);
730 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
733 if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
734 Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
735 db_strerror(jcr->db));
736 jcr->setJobStatus(JS_ErrorTerminated);
739 update_bootstrap_file(wjcr);
741 if (!db_get_job_volume_names(wjcr, wjcr->db, wjcr->jr.JobId, &wjcr->VolumeName)) {
743 * Note, if the job has failed, most likely it did not write any
744 * tape, so suppress this "error" message since in that case
745 * it is normal. Or look at it the other way, only for a
746 * normal exit should we complain about this error.
748 if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
749 Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(wjcr->db));
751 wjcr->VolumeName[0] = 0; /* none */
754 if (wjcr->VolumeName[0]) {
755 /* Find last volume name. Multiple vols are separated by | */
756 char *p = strrchr(wjcr->VolumeName, '|');
760 p = wjcr->VolumeName; /* no |, take full name */
762 bstrncpy(mr.VolumeName, p, sizeof(mr.VolumeName));
763 if (!db_get_media_record(jcr, jcr->db, &mr)) {
764 Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
765 mr.VolumeName, db_strerror(jcr->db));
769 /* We keep all information in the catalog because most of the work is
770 * done, and users might restore things from what we have
773 jcr->setJobStatus(JS_ErrorTerminated);
774 Mmsg(query, "UPDATE Job SET JobStatus='%c' WHERE JobId=%s",
775 JS_ErrorTerminated, new_jobid);
776 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
779 switch (jcr->JobStatus) {
781 if (jcr->JobErrors || jcr->SDErrors) {
782 term_msg = _("%s OK -- with warnings");
784 term_msg = _("%s OK");
788 case JS_ErrorTerminated:
789 term_msg = _("*** %s Error ***");
790 msg_type = M_ERROR; /* Generate error message */
791 if (jcr->store_bsock) {
792 jcr->store_bsock->signal(BNET_TERMINATE);
793 if (jcr->SD_msg_chan_started) {
794 pthread_cancel(jcr->SD_msg_chan);
797 if (wjcr->store_bsock) {
798 wjcr->store_bsock->signal(BNET_TERMINATE);
799 if (wjcr->SD_msg_chan_started) {
800 pthread_cancel(wjcr->SD_msg_chan);
805 term_msg = _("%s Canceled");
806 if (jcr->store_bsock) {
807 jcr->store_bsock->signal(BNET_TERMINATE);
808 if (jcr->SD_msg_chan_started) {
809 pthread_cancel(jcr->SD_msg_chan);
812 if (wjcr->store_bsock) {
813 wjcr->store_bsock->signal(BNET_TERMINATE);
814 if (wjcr->SD_msg_chan_started) {
815 pthread_cancel(wjcr->SD_msg_chan);
820 term_msg = _("Inappropriate %s term code");
824 if (!goterrors && jcr->getJobType() == JT_MIGRATE && jcr->previous_jr.JobId != 0) {
825 /* Mark previous job as migrated */
826 Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
827 (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
828 db_sql_query(jcr->db, query.c_str(), NULL, NULL);
830 term_msg = _("%s -- no files to %s");
833 bsnprintf(term_code, sizeof(term_code), term_msg, jcr->get_OperationName(), jcr->get_ActionName(0));
834 bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
835 bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
836 RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
840 kbps = (double)jcr->SDJobBytes / (1000 * RunTime);
843 jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
845 /* Edit string for last volume size */
846 if (mr.VolABytes != 0) {
847 Mmsg(vol_info, _("meta: %s (%sB) aligned: %s (%sB)"),
848 edit_uint64_with_commas(mr.VolBytes, ec4),
849 edit_uint64_with_suffix(mr.VolBytes, ec5),
850 edit_uint64_with_commas(mr.VolABytes, ec9),
851 edit_uint64_with_suffix(mr.VolBytes, ec10));
853 Mmsg(vol_info, _("%s (%sB)"),
854 edit_uint64_with_commas(mr.VolBytes, ec4),
855 edit_uint64_with_suffix(mr.VolBytes, ec5));
858 Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
859 " Build OS: %s %s %s\n"
860 " Prev Backup JobId: %s\n"
861 " Prev Backup Job: %s\n"
862 " New Backup JobId: %s\n"
863 " Current JobId: %s\n"
865 " Backup Level: %s%s\n"
867 " FileSet: \"%s\" %s\n"
868 " Read Pool: \"%s\" (From %s)\n"
869 " Read Storage: \"%s\" (From %s)\n"
870 " Write Pool: \"%s\" (From %s)\n"
871 " Write Storage: \"%s\" (From %s)\n"
872 " Catalog: \"%s\" (From %s)\n"
875 " Elapsed time: %s\n"
877 " SD Files Written: %s\n"
878 " SD Bytes Written: %s (%sB)\n"
880 " Volume name(s): %s\n"
881 " Volume Session Id: %d\n"
882 " Volume Session Time: %d\n"
883 " Last Volume Bytes: %s\n"
885 " SD termination status: %s\n"
886 " Termination: %s\n\n"),
887 BACULA, my_name, VERSION, LSMDATE,
888 HOST_OS, DISTNAME, DISTVER,
889 edit_uint64(jcr->previous_jr.JobId, ec6),
890 jcr->previous_jr.Job,
891 wjcr ? edit_uint64(wjcr->jr.JobId, ec7) : "0",
892 edit_uint64(jcr->jr.JobId, ec8),
894 level_to_str(jcr->getJobLevel()), jcr->since,
896 jcr->fileset->name(), jcr->FSCreateTime,
897 jcr->rpool->name(), jcr->rpool_source,
898 jcr->rstore?jcr->rstore->name():"*None*",
899 NPRT(jcr->rstore_source),
900 jcr->pool->name(), jcr->pool_source,
901 jcr->wstore?jcr->wstore->name():"*None*",
902 NPRT(jcr->wstore_source),
903 jcr->catalog->name(), jcr->catalog_source,
906 edit_utime(RunTime, elapsed, sizeof(elapsed)),
908 edit_uint64_with_commas(jcr->SDJobFiles, ec1),
909 edit_uint64_with_commas(jcr->SDJobBytes, ec2),
910 edit_uint64_with_suffix(jcr->SDJobBytes, ec3),
912 wjcr ? wjcr->VolumeName : "",
920 Dmsg0(100, "Leave migrate_cleanup()\n");
923 bool set_mac_wstorage(UAContext *ua, JCR *jcr, POOL *pool, POOL *next_pool,
928 ua->error_msg(_("No Next Pool specification found in Pool \"%s\".\n"),
931 Jmsg(jcr, M_FATAL, 0, _("No Next Pool specification found in Pool \"%s\".\n"),
937 if (!next_pool->storage || next_pool->storage->size() == 0) {
938 Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Next Pool \"%s\".\n"),
943 /* If pool storage specified, use it instead of job storage for backup */
944 copy_wstorage(jcr, next_pool->storage, source);