2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 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.
20 * Bacula Director -- mac.c -- responsible for doing
21 * migration and copy jobs.
23 * Also handles Copy jobs (March MMVIII)
25 * Written by Kern Sibbald, September MMIV
27 * Basic tasks done here:
28 * Open DB and create records for this job.
29 * Open Message Channel with Storage daemon to tell him a job will be starting.
30 * Open connection with Storage daemon and pass him commands
32 * When the Storage daemon finishes the job, update the DB.
39 static const int dbglevel = 10;
40 static char storaddr[] = "storage address=%s port=%d ssl=%d Job=%s Authentication=%s\n";
41 static char OKstore[] = "2000 OK storage\n";
43 /* Imported subroutines */
44 extern int getJob_to_migrate(JCR *jcr);
45 extern bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1,
46 const char *query2, const char *type);
47 extern bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1,
49 extern bool find_jobids_of_pool_uncopied_jobs(JCR *jcr, idpkt *ids);
51 static bool set_mac_next_pool(JCR *jcr, POOL **pool);
54 * Called here before the job is run to do the job
55 * specific setup. Note, one of the important things to
56 * complete in this init code is to make the definitive
57 * choice of input and output storage devices. This is
58 * because immediately after the init, the job is queued
59 * in the jobq.c code, and it checks that all the resources
60 * (storage resources in particular) are available, so these
61 * must all be properly defined.
63 * previous_jr refers to the job DB record of the Job that is
64 * going to be migrated.
65 * prev_job refers to the job resource of the Job that is
66 * going to be migrated.
67 * jcr is the jcr for the current "migration" job. It is a
68 * control job that is put in the DB as a migration job, which
69 * means that this job migrated a previous job to a new job.
70 * No Volume or File data is associated with this control
72 * wjcr refers to the migrate/copy job that is writing and is run by
73 * the current jcr. It is a backup job that writes the
74 * data written for the previous_jr into the new pool. This
75 * job (wjcr) becomes the new backup job that replaces
76 * the original backup job. Note, this jcr is not really run. It
77 * is simply attached to the current jcr. It will show up in
78 * the Director's status output, but not in the SD or FD, both of
79 * which deal only with the current migration job (i.e. jcr).
81 bool do_mac_init(JCR *jcr)
85 JCR *wjcr; /* jcr of writing job */
89 apply_pool_overrides(jcr);
91 if (!allow_duplicate_job(jcr)) {
95 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
96 if (jcr->jr.PoolId == 0) {
97 Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId);
98 Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
102 * Note, at this point, pool is the pool for this job. We
103 * transfer it to rpool (read pool), and a bit later,
104 * pool will be changed to point to the write pool,
105 * which comes from pool->NextPool.
107 jcr->rpool = jcr->pool; /* save read pool */
108 pm_strcpy(jcr->rpool_source, jcr->pool_source);
109 Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
111 if (!get_or_create_fileset_record(jcr)) {
112 Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
113 Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
117 /* If we find a job or jobs to migrate it is previous_jr.JobId */
118 count = getJob_to_migrate(jcr);
123 set_mac_next_pool(jcr, &pool);
124 return true; /* no work */
127 Dmsg1(dbglevel, "Back from getJob_to_migrate JobId=%d\n", (int)jcr->JobId);
129 if (jcr->previous_jr.JobId == 0) {
130 Dmsg1(dbglevel, "JobId=%d no previous JobId\n", (int)jcr->JobId);
131 Jmsg(jcr, M_INFO, 0, _("No previous Job found to %s.\n"), jcr->get_ActionName(0));
132 set_mac_next_pool(jcr, &pool);
133 return true; /* no work */
136 if (create_restore_bootstrap_file(jcr) < 0) {
137 Jmsg(jcr, M_FATAL, 0, _("Create bootstrap file failed.\n"));
141 if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) {
142 jcr->setJobStatus(JS_Terminated);
143 Dmsg1(dbglevel, "JobId=%d expected files == 0\n", (int)jcr->JobId);
144 if (jcr->previous_jr.JobId == 0) {
145 Jmsg(jcr, M_INFO, 0, _("No previous Job found to %s.\n"), jcr->get_ActionName(0));
147 Jmsg(jcr, M_INFO, 0, _("Previous Job has no data to %s.\n"), jcr->get_ActionName(0));
149 set_mac_next_pool(jcr, &pool);
150 return true; /* no work */
154 Dmsg5(dbglevel, "JobId=%d: Current: Name=%s JobId=%d Type=%c Level=%c\n",
156 jcr->jr.Name, (int)jcr->jr.JobId,
157 jcr->jr.JobType, jcr->jr.JobLevel);
160 job = (JOB *)GetResWithName(R_JOB, jcr->jr.Name);
161 prev_job = (JOB *)GetResWithName(R_JOB, jcr->previous_jr.Name);
164 Jmsg(jcr, M_FATAL, 0, _("Job resource not found for \"%s\".\n"), jcr->jr.Name);
168 Jmsg(jcr, M_FATAL, 0, _("Previous Job resource not found for \"%s\".\n"),
169 jcr->previous_jr.Name);
174 /* Create a write jcr */
175 wjcr = jcr->wjcr = new_jcr(sizeof(JCR), dird_free_jcr);
176 memcpy(&wjcr->previous_jr, &jcr->previous_jr, sizeof(wjcr->previous_jr));
179 * Turn the wjcr into a "real" job that takes on the aspects of
180 * the previous backup job "prev_job".
182 set_jcr_defaults(wjcr, prev_job);
183 /* fix MA 987 cannot copy/migrate jobs with a Level=VF in the job resource
184 * If the prev_job level definition is VirtualFull,
185 * change it to Incremental, otherwise the writing SD would do a VF
187 if (wjcr->getJobLevel() == L_VIRTUAL_FULL) {
188 wjcr->setJobLevel(L_INCREMENTAL);
191 /* Don't check for duplicates on this jobs. We do it before setup_job(),
192 * because we check allow_duplicate_job() here.
194 wjcr->IgnoreDuplicateJobChecking = true;
196 if (!setup_job(wjcr)) {
197 Jmsg(jcr, M_FATAL, 0, _("setup job failed.\n"));
201 /* Now reset the job record from the previous job */
202 memcpy(&wjcr->jr, &jcr->previous_jr, sizeof(wjcr->jr));
203 /* Update the jr to reflect the new values of PoolId and JobId. */
204 wjcr->jr.PoolId = jcr->jr.PoolId;
205 wjcr->jr.JobId = wjcr->JobId;
206 wjcr->sd_client = true;
207 //wjcr->setJobType(jcr->getJobType());
208 wjcr->spool_data = job->spool_data; /* turn on spooling if requested in job */
209 wjcr->spool_size = jcr->spool_size;
212 /* Don't let WatchDog checks Max*Time value on this Job */
213 wjcr->no_maxtime = true;
214 Dmsg4(dbglevel, "wjcr: Name=%s JobId=%d Type=%c Level=%c\n",
215 wjcr->jr.Name, (int)wjcr->jr.JobId,
216 wjcr->jr.JobType, wjcr->jr.JobLevel);
218 if (set_mac_next_pool(jcr, &pool)) {
219 /* If pool storage specified, use it for restore */
220 copy_rstorage(wjcr, pool->storage, _("Pool resource"));
221 copy_rstorage(jcr, pool->storage, _("Pool resource"));
223 wjcr->pool = jcr->pool;
224 wjcr->next_pool = jcr->next_pool;
225 wjcr->jr.PoolId = jcr->jr.PoolId;
232 * set_mac_next_pool() called by do_mac_init()
233 * at differents stages.
234 * The idea here is to make a common subroutine for the
235 * NextPool's search code and to permit do_mac_init()
236 * to return with NextPool set in jcr struct.
238 static bool set_mac_next_pool(JCR *jcr, POOL **retpool)
245 * Get the PoolId used with the original job. Then
246 * find the pool name from the database record.
248 memset(&pr, 0, sizeof(pr));
249 pr.PoolId = jcr->jr.PoolId;
250 if (!db_get_pool_record(jcr, jcr->db, &pr)) {
251 Jmsg(jcr, M_FATAL, 0, _("Pool for JobId %s not in database. ERR=%s\n"),
252 edit_int64(pr.PoolId, ed1), db_strerror(jcr->db));
255 /* Get the pool resource corresponding to the original job */
256 pool = (POOL *)GetResWithName(R_POOL, pr.Name);
259 Jmsg(jcr, M_FATAL, 0, _("Pool resource \"%s\" not found.\n"), pr.Name);
263 if (!apply_wstorage_overrides(jcr, pool)) {
267 Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
273 * Send storage address and authentication to deblock the other
276 static bool send_store_addr_to_sd(JCR *jcr, char *Job, char *sd_auth_key,
277 STORE *store, char *store_address, uint32_t store_port)
279 int tls_need = BNET_TLS_NONE;
281 /* TLS Requirement */
282 if (store->tls_enable) {
283 if (store->tls_require) {
284 tls_need = BNET_TLS_REQUIRED;
286 tls_need = BNET_TLS_OK;
291 * Send Storage address to the SD client
293 Dmsg2(200, "=== Job=%s sd auth key=%s\n", Job, sd_auth_key);
294 jcr->store_bsock->fsend(storaddr, store_address, store_port,
295 tls_need, Job, sd_auth_key);
296 if (!response(jcr, jcr->store_bsock, OKstore, "Storage", DISPLAY_ERROR)) {
297 Dmsg4(050, "Response fail for: JobId=%d storeaddr=%s:%d Job=%s\n",
298 jcr->JobId, store_address, store_port, Job);
299 Jmsg3(jcr, M_FATAL, 0, "Response failure: storeddr=%s:%d Job=%s\n",
300 store_address, store_port, Job);
308 * Do a Migration and Copy of a previous job
310 * Returns: false on failure
313 bool do_mac(JCR *jcr)
317 JCR *wjcr = jcr->wjcr; /* newly migrated job */
324 * If wjcr is NULL, there is nothing to do for this job,
325 * so set a normal status, cleanup and return OK.
328 jcr->setJobStatus(JS_Terminated);
329 mac_cleanup(jcr, JS_Terminated, JS_Terminated);
333 if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
334 Jmsg(jcr, M_FATAL, 0, _("Could not get job record for JobId %s to %s. ERR=%s"),
335 edit_int64(jcr->previous_jr.JobId, ed1),
336 jcr->get_ActionName(0),
337 db_strerror(jcr->db));
338 jcr->setJobStatus(JS_Terminated);
339 mac_cleanup(jcr, JS_Terminated, JS_Terminated);
342 /* Make sure this job was not already migrated */
343 if (jcr->previous_jr.JobType != JT_BACKUP &&
344 jcr->previous_jr.JobType != JT_JOB_COPY) {
345 Jmsg(jcr, M_INFO, 0, _("JobId %s already %s probably by another Job. %s stopped.\n"),
346 edit_int64(jcr->previous_jr.JobId, ed1),
347 jcr->get_ActionName(1),
348 jcr->get_OperationName());
349 jcr->setJobStatus(JS_Terminated);
350 mac_cleanup(jcr, JS_Terminated, JS_Terminated);
354 /* Print Job Start message */
355 Jmsg(jcr, M_INFO, 0, _("Start %s JobId %s, Job=%s\n"),
356 jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
358 Dmsg3(200, "Start %s JobId %s, Job=%s\n",
359 jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
363 * Now separate the read and write storages. jcr has no wstor...
364 * they all go into wjcr.
366 free_rwstorage(wjcr);
368 wjcr->wstore = jcr->wstore;
370 wjcr->wstorage = jcr->wstorage;
371 jcr->wstorage = NULL;
373 /* TODO: See priority with bandwidth parameter */
374 if (jcr->job->max_bandwidth > 0) {
375 jcr->max_bandwidth = jcr->job->max_bandwidth;
376 } else if (jcr->client && jcr->client->max_bandwidth > 0) {
377 jcr->max_bandwidth = jcr->client->max_bandwidth;
380 if (jcr->max_bandwidth > 0) {
381 send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
385 * Open a message channel connection with the Storage
386 * daemon. This is to let him know that our client
387 * will be contacting him for a backup session.
390 jcr->setJobStatus(JS_WaitSD);
391 wjcr->setJobStatus(JS_WaitSD);
394 * Start conversation with write Storage daemon
396 Dmsg0(200, "Connect to write (wjcr) storage daemon.\n");
397 if (!connect_to_storage_daemon(wjcr, 10, SDConnectTimeout, 1)) {
400 wsd = wjcr->store_bsock;
403 * Start conversation with read Storage daemon
405 Dmsg1(200, "Connect to read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
406 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
409 sd = jcr->store_bsock;
411 jcr->sd_calls_client = jcr->client->sd_calls_client;
414 Dmsg2(dbglevel, "Read store=%s, write store=%s\n",
415 ((STORE *)jcr->rstorage->first())->name(),
416 ((STORE *)wjcr->wstorage->first())->name());
419 * Now start a job with the read Storage daemon sending the bsr.
420 * This call returns the sd_auth_key
422 Dmsg1(200, "Start job with read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
423 if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL, /*send_bsr*/true)) {
426 Dmsg0(150, "Read storage daemon connection OK\n");
428 if (jcr->sd_calls_client) {
429 wjcr->sd_calls_client = true;
430 wjcr->sd_client = false;
432 wjcr->sd_calls_client = true;
433 wjcr->sd_client = true;
437 * Now start a job with the write Storage daemon sending.
439 Dmsg1(200, "Start Job with write (wjcr) storage daemon. Jid=%d\n", jcr->JobId);
440 if (!start_storage_daemon_job(wjcr, NULL, wjcr->wstorage, /*no_send_bsr*/false)) {
443 Dmsg0(150, "Write storage daemon connection OK\n");
446 /* Declare the job started to start the MaxRunTime check */
447 jcr->setJobStarted();
450 * We re-update the job start record so that the start
451 * time is set after the run before job. This avoids
452 * that any files created by the run before job will
453 * be saved twice. They will be backed up in the current
454 * job, but not in the next one unless they are changed.
455 * Without this, they will be backed up in this job and
456 * in the next job run because in that case, their date
457 * is after the start of this run.
459 jcr->start_time = time(NULL);
460 jcr->jr.StartTime = jcr->start_time;
461 jcr->jr.JobTDate = jcr->start_time;
462 jcr->setJobStatus(JS_Running);
464 /* Update job start record for this mac control job */
465 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
466 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
470 /* Declare the job started to start the MaxRunTime check */
471 jcr->setJobStarted();
473 wjcr->start_time = time(NULL);
474 wjcr->jr.StartTime = wjcr->start_time;
475 wjcr->jr.JobTDate = wjcr->start_time;
476 wjcr->setJobStatus(JS_Running);
479 /* Update job start record for the real mac backup job */
480 if (!db_update_job_start_record(wjcr, wjcr->db, &wjcr->jr)) {
481 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(wjcr->db));
485 Dmsg4(dbglevel, "wjcr: Name=%s JobId=%d Type=%c Level=%c\n",
486 wjcr->jr.Name, (int)wjcr->jr.JobId,
487 wjcr->jr.JobType, wjcr->jr.JobLevel);
490 if (jcr->sd_calls_client) {
492 * Reading SD must call the "client" i.e. the writing SD
494 if (jcr->SDVersion < 3) {
495 Jmsg(jcr, M_FATAL, 0, _("The Storage daemon does not support SDCallsClient.\n"));
499 /* Setup the storage address and port */
500 store = wjcr->wstore;
501 if (store->SDDport == 0) {
502 store->SDDport = store->SDport;
504 store_address = store->address; /* note: store points to wstore */
506 Dmsg2(200, "Start write message thread jid=%d Job=%s\n", wjcr->JobId, wjcr->Job);
507 if (!run_storage_and_start_message_thread(wjcr, wsd)) {
511 store_port = store->SDDport;
514 * Send writing SD address to the reading SD
516 /* Send and wait for connection */
517 /* ***FIXME*** this should probably be jcr->rstore, store_address, ...
518 * to get TLS right */
519 if (!send_store_addr_to_sd(jcr, wjcr->Job, wjcr->sd_auth_key,
520 store, store_address, store_port)) {
524 /* Start read message thread */
525 Dmsg2(200, "Start read message thread jid=%d Job=%s\n", jcr->JobId, jcr->Job);
526 if (!run_storage_and_start_message_thread(jcr, sd)) {
532 * Writing SD must simulate an FD and call the reading SD
534 * Send Storage daemon address to the writing SD
537 if (store->SDDport == 0) {
538 store->SDDport = store->SDport;
540 store_address = get_storage_address(jcr->client, store);
541 store_port = store->SDDport;
543 /* Start read message thread */
544 Dmsg2(200, "Start read message thread jid=%d Job=%s\n", jcr->JobId, jcr->Job);
545 if (!run_storage_and_start_message_thread(jcr, sd)) {
549 /* Attempt connection for one hour */
550 if (!send_store_addr_to_sd(wjcr, jcr->Job, jcr->sd_auth_key,
551 store, store_address, store_port)) {
554 /* Start write message thread */
555 Dmsg2(200, "Start write message thread jid=%d Job=%s\n", wjcr->JobId, wjcr->Job);
556 if (!run_storage_and_start_message_thread(wjcr, wsd)) {
561 jcr->setJobStatus(JS_Running);
562 wjcr->setJobStatus(JS_Running);
564 /* Pickup Job termination data */
565 /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
566 wait_for_storage_daemon_termination(wjcr);
567 wjcr->setJobStatus(wjcr->SDJobStatus);
568 wait_for_storage_daemon_termination(jcr);
569 jcr->setJobStatus(jcr->SDJobStatus);
570 db_write_batch_file_records(wjcr); /* used by bulk batch file insert */
572 ok = jcr->is_JobStatus(JS_Terminated) && wjcr->is_JobStatus(JS_Terminated);
575 /* Put back jcr write storages for proper cleanup */
576 jcr->wstorage = wjcr->wstorage;
577 jcr->wstore = wjcr->wstore;
579 wjcr->wstorage = NULL;
580 wjcr->file_bsock = NULL;
583 mac_cleanup(jcr, jcr->JobStatus, wjcr->JobStatus);
589 * Called from mac_sql.c for each migration/copy job to start
591 void start_mac_job(JCR *jcr)
593 UAContext *ua = new_ua_context(jcr);
595 char args[MAX_NAME_LENGTH + 50];
598 Mmsg(ua->cmd, "run job=\"%s\" jobid=%s ignoreduplicatecheck=yes pool=\"%s\"",
599 jcr->job->name(), edit_uint64(jcr->MigrateJobId, ed1),
601 if (jcr->next_pool) {
602 bsnprintf(args, sizeof(args), " nextpool=\"%s\"", jcr->next_pool->name());
603 pm_strcat(ua->cmd, args);
605 Dmsg2(dbglevel, "=============== %s cmd=%s\n", jcr->get_OperationName(), ua->cmd);
606 parse_ua_args(ua); /* parse command */
607 JobId_t jobid = run_cmd(ua, ua->cmd);
609 Jmsg(jcr, M_ERROR, 0, _("Could not start migration/copy job.\n"));
611 Jmsg(jcr, M_INFO, 0, _("%s JobId %d started.\n"), jcr->get_OperationName(), (int)jobid);
617 * Release resources allocated during backup.
619 /* ***FIXME*** implement writeTermCode */
620 void mac_cleanup(JCR *jcr, int TermCode, int writeTermCode)
622 char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
623 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], elapsed[50];
624 char ec6[50], ec7[50], ec8[50], ec9[30], ec10[30];
625 char sd_term_msg[100];
628 int msg_type = M_INFO;
632 bool goterrors=false;
633 JCR *wjcr = jcr->wjcr;
634 POOL_MEM query(PM_MESSAGE);
637 remove_dummy_jobmedia_records(jcr);
639 Dmsg2(100, "Enter mac_cleanup %d %c\n", TermCode, TermCode);
640 update_job_end(jcr, TermCode);
643 * Check if we actually did something.
644 * wjcr is jcr of the newly migrated job.
647 char old_jobid[50], new_jobid[50];
649 edit_uint64(jcr->previous_jr.JobId, old_jobid);
650 edit_uint64(wjcr->jr.JobId, new_jobid);
652 wjcr->JobFiles = jcr->JobFiles = wjcr->SDJobFiles;
653 wjcr->JobBytes = jcr->JobBytes = wjcr->SDJobBytes;
654 wjcr->jr.RealEndTime = 0;
655 wjcr->jr.PriorJobId = jcr->previous_jr.JobId;
656 wjcr->JobErrors += wjcr->SDErrors;
657 update_job_end(wjcr, TermCode);
659 /* Update final items to set them to the previous job's values */
660 Mmsg(query, "UPDATE Job SET StartTime='%s',EndTime='%s',"
661 "JobTDate=%s WHERE JobId=%s",
662 jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime,
663 edit_uint64(jcr->previous_jr.JobTDate, ec1),
665 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
667 goterrors = jcr->SDErrors > 0 || jcr->JobErrors > 0 ||
668 jcr->SDJobStatus == JS_Canceled ||
669 jcr->SDJobStatus == JS_ErrorTerminated ||
670 jcr->SDJobStatus == JS_FatalError;
672 if (goterrors && jcr->getJobType() == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
673 Jmsg(jcr, M_WARNING, 0, _("Found errors during the migration process. "
674 "The original job %s will be kept in the catalog "
675 "and the Migration job will be marked in Error\n"), old_jobid);
679 * If we terminated a migration normally:
680 * - mark the previous job as migrated
681 * - move any Log records to the new JobId
682 * - Purge the File records from the previous job
684 if (!goterrors && jcr->getJobType() == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
685 Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
686 (char)JT_MIGRATED_JOB, old_jobid);
687 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
688 UAContext *ua = new_ua_context(jcr);
689 /* Move JobLog to new JobId */
690 Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
691 new_jobid, old_jobid);
692 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
694 /* Move RestoreObjects */
695 Mmsg(query, "UPDATE RestoreObject SET JobId=%s WHERE JobId=%s",
696 new_jobid, old_jobid);
697 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
699 if (jcr->job->PurgeMigrateJob) {
700 /* Purge old Job record */
701 purge_jobs_from_catalog(ua, old_jobid);
703 /* Purge all old file records, but leave Job record */
704 purge_files_from_jobs(ua, old_jobid);
711 * If we terminated a Copy (rather than a Migration) normally:
712 * - copy any Log records to the new JobId
713 * - set type="Job Copy" for the new job
715 if (goterrors || (jcr->getJobType() == JT_COPY && jcr->JobStatus == JS_Terminated)) {
716 /* Copy JobLog to new JobId */
717 Mmsg(query, "INSERT INTO Log (JobId, Time, LogText ) "
718 "SELECT %s, Time, LogText FROM Log WHERE JobId=%s",
719 new_jobid, old_jobid);
720 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
722 /* We are in a real copy job */
723 Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
724 (char)JT_JOB_COPY, new_jobid);
725 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
727 /* Copy RestoreObjects */
728 Mmsg(query, "INSERT INTO RestoreObject (ObjectName,PluginName,RestoreObject,"
729 "ObjectLength,ObjectFullLength,ObjectIndex,ObjectType,"
730 "ObjectCompression,FileIndex,JobId) "
731 "SELECT ObjectName,PluginName,RestoreObject,"
732 "ObjectLength,ObjectFullLength,ObjectIndex,ObjectType,"
733 "ObjectCompression,FileIndex,%s FROM RestoreObject WHERE JobId=%s",
734 new_jobid, old_jobid);
735 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
738 if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
739 Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
740 db_strerror(jcr->db));
741 jcr->setJobStatus(JS_ErrorTerminated);
744 update_bootstrap_file(wjcr);
746 if (!db_get_job_volume_names(wjcr, wjcr->db, wjcr->jr.JobId, &wjcr->VolumeName)) {
748 * Note, if the job has failed, most likely it did not write any
749 * tape, so suppress this "error" message since in that case
750 * it is normal. Or look at it the other way, only for a
751 * normal exit should we complain about this error.
753 if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
754 Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(wjcr->db));
756 wjcr->VolumeName[0] = 0; /* none */
759 if (wjcr->VolumeName[0]) {
760 /* Find last volume name. Multiple vols are separated by | */
761 char *p = strrchr(wjcr->VolumeName, '|');
765 p = wjcr->VolumeName; /* no |, take full name */
767 bstrncpy(mr.VolumeName, p, sizeof(mr.VolumeName));
768 if (!db_get_media_record(jcr, jcr->db, &mr)) {
769 Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
770 mr.VolumeName, db_strerror(jcr->db));
774 /* We keep all information in the catalog because most of the work is
775 * done, and users might restore things from what we have
778 jcr->setJobStatus(JS_ErrorTerminated);
779 Mmsg(query, "UPDATE Job SET JobStatus='%c' WHERE JobId=%s",
780 JS_ErrorTerminated, new_jobid);
781 db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
784 switch (jcr->JobStatus) {
786 if (jcr->JobErrors || jcr->SDErrors) {
787 Mmsg(term_msg, _("%%s OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
789 Mmsg(term_msg, _("%%s OK"));
793 case JS_ErrorTerminated:
794 Mmsg(term_msg, _("*** %%s Error ***"));
795 msg_type = M_ERROR; /* Generate error message */
796 if (jcr->store_bsock) {
797 jcr->store_bsock->signal(BNET_TERMINATE);
798 if (jcr->SD_msg_chan_started) {
799 pthread_cancel(jcr->SD_msg_chan);
802 if (wjcr->store_bsock) {
803 wjcr->store_bsock->signal(BNET_TERMINATE);
804 if (wjcr->SD_msg_chan_started) {
805 pthread_cancel(wjcr->SD_msg_chan);
810 Mmsg(term_msg, _("%%s Canceled"));
811 if (jcr->store_bsock) {
812 jcr->store_bsock->signal(BNET_TERMINATE);
813 if (jcr->SD_msg_chan_started) {
814 pthread_cancel(jcr->SD_msg_chan);
817 if (wjcr->store_bsock) {
818 wjcr->store_bsock->signal(BNET_TERMINATE);
819 if (wjcr->SD_msg_chan_started) {
820 pthread_cancel(wjcr->SD_msg_chan);
825 Mmsg(term_msg, _("Inappropriate %s term code"));
829 if (!goterrors && jcr->getJobType() == JT_MIGRATE && jcr->previous_jr.JobId != 0) {
830 /* Mark previous job as migrated */
831 Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
832 (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
833 db_sql_query(jcr->db, query.c_str(), NULL, NULL);
835 Mmsg(term_msg, _("%%s -- no files to %%s"));
838 Mmsg(term_code, term_msg.c_str(), jcr->get_OperationName(), jcr->get_ActionName(0));
839 bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
840 bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
841 RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
845 kbps = (double)jcr->SDJobBytes / (1000.0 * (double)RunTime);
847 jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
849 /* Edit string for last volume size */
850 if (mr.VolABytes != 0) {
851 Mmsg(vol_info, _("meta: %s (%sB) aligned: %s (%sB)"),
852 edit_uint64_with_commas(mr.VolBytes, ec4),
853 edit_uint64_with_suffix(mr.VolBytes, ec5),
854 edit_uint64_with_commas(mr.VolABytes, ec9),
855 edit_uint64_with_suffix(mr.VolBytes, ec10));
857 Mmsg(vol_info, _("%s (%sB)"),
858 edit_uint64_with_commas(mr.VolBytes, ec4),
859 edit_uint64_with_suffix(mr.VolBytes, ec5));
862 Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
863 " Build OS: %s %s %s\n"
864 " Prev Backup JobId: %s\n"
865 " Prev Backup Job: %s\n"
866 " New Backup JobId: %s\n"
867 " Current JobId: %s\n"
869 " Backup Level: %s%s\n"
871 " FileSet: \"%s\" %s\n"
872 " Read Pool: \"%s\" (From %s)\n"
873 " Read Storage: \"%s\" (From %s)\n"
874 " Write Pool: \"%s\" (From %s)\n"
875 " Write Storage: \"%s\" (From %s)\n"
876 " Catalog: \"%s\" (From %s)\n"
879 " Elapsed time: %s\n"
881 " SD Files Written: %s\n"
882 " SD Bytes Written: %s (%sB)\n"
884 " Volume name(s): %s\n"
885 " Volume Session Id: %d\n"
886 " Volume Session Time: %d\n"
887 " Last Volume Bytes: %s\n"
889 " SD termination status: %s\n"
890 " Termination: %s\n\n"),
891 BACULA, my_name, VERSION, LSMDATE,
892 HOST_OS, DISTNAME, DISTVER,
893 edit_uint64(jcr->previous_jr.JobId, ec6),
894 jcr->previous_jr.Job,
895 wjcr ? edit_uint64(wjcr->jr.JobId, ec7) : "0",
896 edit_uint64(jcr->jr.JobId, ec8),
898 level_to_str(jcr->getJobLevel()), jcr->since,
900 jcr->fileset->name(), jcr->FSCreateTime,
901 jcr->rpool->name(), jcr->rpool_source,
902 jcr->rstore?jcr->rstore->name():"*None*",
903 NPRT(jcr->rstore_source),
904 jcr->pool->name(), jcr->pool_source,
905 jcr->wstore?jcr->wstore->name():"*None*",
906 NPRT(jcr->wstore_source),
907 jcr->catalog->name(), jcr->catalog_source,
910 edit_utime(RunTime, elapsed, sizeof(elapsed)),
912 edit_uint64_with_commas(jcr->SDJobFiles, ec1),
913 edit_uint64_with_commas(jcr->SDJobBytes, ec2),
914 edit_uint64_with_suffix(jcr->SDJobBytes, ec3),
916 wjcr ? wjcr->VolumeName : "",
924 Dmsg0(100, "Leave migrate_cleanup()\n");
927 bool set_mac_wstorage(UAContext *ua, JCR *jcr, POOL *pool, POOL *next_pool,
932 ua->error_msg(_("No Next Pool specification found in Pool \"%s\".\n"),
935 Jmsg(jcr, M_FATAL, 0, _("No Next Pool specification found in Pool \"%s\".\n"),
941 if (!next_pool->storage || next_pool->storage->size() == 0) {
942 Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Next Pool \"%s\".\n"),
947 /* If pool storage specified, use it instead of job storage for backup */
948 copy_wstorage(jcr, next_pool->storage, source);