1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
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.
8 
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.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *   Bacula Director -- mac.c -- responsible for doing
21  *     migration and copy jobs.
22  *
23  *   Also handles Copy jobs (March MMVIII)
24  *
25  *   Written by Kern Sibbald, September MMIV
26  *
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
31  *       to do the backup.
32  *     When the Storage daemon finishes the job, update the DB.
33  */
34 
35 #include "bacula.h"
36 #include "dird.h"
37 #include "ua.h"
38 
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";
42 
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,
48                  const char *type);
49 extern bool find_jobids_of_pool_uncopied_jobs(JCR *jcr, idpkt *ids);
50 
51 static bool set_mac_next_pool(JCR *jcr, POOL **pool);
52 
53 /*
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.
62  *
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
71  *    job.
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).
80  */
do_mac_init(JCR * jcr)81 bool do_mac_init(JCR *jcr)
82 {
83    POOL *pool = NULL;
84    JOB *job, *prev_job;
85    JCR *wjcr;                     /* jcr of writing job */
86    int count;
87 
88 
89    apply_pool_overrides(jcr);
90 
91    if (!allow_duplicate_job(jcr)) {
92       return false;
93    }
94 
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"));
99       return false;
100    }
101    /*
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.
106     */
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);
110 
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"));
114       return false;
115    }
116 
117    /* If we find a job or jobs to migrate it is previous_jr.JobId */
118    count = getJob_to_migrate(jcr);
119    if (count < 0) {
120       return false;
121    }
122    if (count == 0) {
123       set_mac_next_pool(jcr, &pool);
124       return true;                    /* no work */
125    }
126 
127    Dmsg1(dbglevel, "Back from getJob_to_migrate JobId=%d\n", (int)jcr->JobId);
128 
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 */
134    }
135 
136    if (create_restore_bootstrap_file(jcr) < 0) {
137       Jmsg(jcr, M_FATAL, 0, _("Create bootstrap file failed.\n"));
138       return false;
139    }
140 
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));
146       } else {
147          Jmsg(jcr, M_INFO, 0, _("Previous Job has no data to %s.\n"), jcr->get_ActionName(0));
148       }
149       set_mac_next_pool(jcr, &pool);
150       return true;                    /* no work */
151    }
152 
153 
154    Dmsg5(dbglevel, "JobId=%d: Current: Name=%s JobId=%d Type=%c Level=%c\n",
155       (int)jcr->JobId,
156       jcr->jr.Name, (int)jcr->jr.JobId,
157       jcr->jr.JobType, jcr->jr.JobLevel);
158 
159    LockRes();
160    job = (JOB *)GetResWithName(R_JOB, jcr->jr.Name);
161    prev_job = (JOB *)GetResWithName(R_JOB, jcr->previous_jr.Name);
162    UnlockRes();
163    if (!job) {
164       Jmsg(jcr, M_FATAL, 0, _("Job resource not found for \"%s\".\n"), jcr->jr.Name);
165       return false;
166    }
167    if (!prev_job) {
168       Jmsg(jcr, M_FATAL, 0, _("Previous Job resource not found for \"%s\".\n"),
169            jcr->previous_jr.Name);
170       return false;
171    }
172 
173 
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));
177 
178    /*
179     * Turn the wjcr into a "real" job that takes on the aspects of
180     *   the previous backup job "prev_job".
181     */
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
186     */
187    if (wjcr->getJobLevel() == L_VIRTUAL_FULL) {
188       wjcr->setJobLevel(L_INCREMENTAL);
189    }
190 
191    /* Don't check for duplicates on this jobs. We do it before setup_job(),
192     * because we check allow_duplicate_job() here.
193     */
194    wjcr->IgnoreDuplicateJobChecking = true;
195 
196    if (!setup_job(wjcr)) {
197       Jmsg(jcr, M_FATAL, 0, _("setup job failed.\n"));
198       return false;
199    }
200 
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->setJobLevel(jcr->getJobLevel());
209    wjcr->spool_data = job->spool_data;     /* turn on spooling if requested in job */
210    wjcr->spool_size = jcr->spool_size;
211    jcr->spool_size = 0;
212 
213    /* Don't let WatchDog checks Max*Time value on this Job */
214    wjcr->no_maxtime = true;
215    Dmsg4(dbglevel, "wjcr: Name=%s JobId=%d Type=%c Level=%c\n",
216       wjcr->jr.Name, (int)wjcr->jr.JobId,
217       wjcr->jr.JobType, wjcr->jr.JobLevel);
218 
219    if (set_mac_next_pool(jcr, &pool)) {
220       /* If pool storage specified, use it for restore */
221       copy_rstorage(wjcr, pool->storage, _("Pool resource"));
222       copy_rstorage(jcr, pool->storage, _("Pool resource"));
223 
224       wjcr->pool = jcr->pool;
225       wjcr->next_pool = jcr->next_pool;
226       wjcr->jr.PoolId = jcr->jr.PoolId;
227    }
228 
229    return true;
230 }
231 
232 /*
233  * set_mac_next_pool() called by do_mac_init()
234  * at differents stages.
235  * The  idea here is to make a common subroutine for the
236  *   NextPool's search code and to permit do_mac_init()
237  *   to return with NextPool set in jcr struct.
238  */
set_mac_next_pool(JCR * jcr,POOL ** retpool)239 static bool set_mac_next_pool(JCR *jcr, POOL **retpool)
240 {
241    POOL_DBR pr;
242    POOL *pool;
243    char ed1[100];
244 
245    /*
246     * Get the PoolId used with the original job. Then
247     *  find the pool name from the database record.
248     */
249    bmemset(&pr, 0, sizeof(pr));
250    pr.PoolId = jcr->jr.PoolId;
251    if (!db_get_pool_record(jcr, jcr->db, &pr)) {
252       Jmsg(jcr, M_FATAL, 0, _("Pool for JobId %s not in database. ERR=%s\n"),
253             edit_int64(pr.PoolId, ed1), db_strerror(jcr->db));
254          return false;
255    }
256    /* Get the pool resource corresponding to the original job */
257    pool = (POOL *)GetResWithName(R_POOL, pr.Name);
258    *retpool = pool;
259    if (!pool) {
260       Jmsg(jcr, M_FATAL, 0, _("Pool resource \"%s\" not found.\n"), pr.Name);
261       return false;
262    }
263 
264    if (!apply_wstorage_overrides(jcr, pool)) {
265       return false;
266    }
267 
268    Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
269 
270    return true;
271 }
272 
273 /*
274  * Send storage address and authentication to deblock the other
275  *   job.
276  */
send_store_addr_to_sd(JCR * jcr,char * Job,char * sd_auth_key,STORE * store,char * store_address,uint32_t store_port)277 static bool send_store_addr_to_sd(JCR *jcr, char *Job, char *sd_auth_key,
278                  STORE *store, char *store_address, uint32_t store_port)
279 {
280    int tls_need = BNET_TLS_NONE;
281 
282    /* TLS Requirement */
283    if (store->tls_enable) {
284       if (store->tls_require) {
285          tls_need = BNET_TLS_REQUIRED;
286       } else {
287          tls_need = BNET_TLS_OK;
288       }
289    }
290 
291    /*
292     * Send Storage address to the SD client
293     */
294    Dmsg2(200, "=== Job=%s sd auth key=%s\n", Job, sd_auth_key);
295    jcr->store_bsock->fsend(storaddr, store_address, store_port,
296       tls_need, Job, sd_auth_key);
297    if (!response(jcr, jcr->store_bsock, OKstore, "Storage", DISPLAY_ERROR)) {
298       Dmsg4(050, "Response fail for: JobId=%d storeaddr=%s:%d Job=%s\n",
299            jcr->JobId, store_address, store_port, Job);
300       Jmsg3(jcr, M_FATAL, 0, "Response failure: storeddr=%s:%d Job=%s\n",
301             store_address, store_port, Job);
302 
303       return false;
304    }
305    return true;
306 }
307 
308 /*
309  * Do a Migration and Copy of a previous job
310  *
311  *  Returns:  false on failure
312  *            true  on success
313  */
do_mac(JCR * jcr)314 bool do_mac(JCR *jcr)
315 {
316    char ed1[100];
317    BSOCK *sd, *wsd;
318    JCR *wjcr = jcr->wjcr;    /* newly migrated job */
319    bool ok = false;
320    STORE *store;
321    char *store_address;
322    uint32_t store_port;
323 
324    /*
325     * If wjcr is NULL, there is nothing to do for this job,
326     *  so set a normal status, cleanup and return OK.
327     */
328    if (!wjcr) {
329       jcr->setJobStatus(JS_Terminated);
330       mac_cleanup(jcr, JS_Terminated, JS_Terminated);
331       return true;
332    }
333 
334    if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
335       Jmsg(jcr, M_FATAL, 0, _("Could not get job record for JobId %s to %s. ERR=%s"),
336            edit_int64(jcr->previous_jr.JobId, ed1),
337            jcr->get_ActionName(0),
338            db_strerror(jcr->db));
339       jcr->setJobStatus(JS_Terminated);
340       mac_cleanup(jcr, JS_Terminated, JS_Terminated);
341       return true;
342    }
343    /* Make sure this job was not already migrated */
344    if (jcr->previous_jr.JobType != JT_BACKUP &&
345        jcr->previous_jr.JobType != JT_JOB_COPY) {
346       Jmsg(jcr, M_INFO, 0, _("JobId %s already %s probably by another Job. %s stopped.\n"),
347          edit_int64(jcr->previous_jr.JobId, ed1),
348          jcr->get_ActionName(1),
349          jcr->get_OperationName());
350       jcr->setJobStatus(JS_Terminated);
351       mac_cleanup(jcr, JS_Terminated, JS_Terminated);
352       return true;
353    }
354 
355    /* Print Job Start message */
356    Jmsg(jcr, M_INFO, 0, _("Start %s JobId %s, Job=%s\n"),
357         jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
358 
359    Dmsg3(200, "Start %s JobId %s, Job=%s\n",
360         jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
361 
362 
363    /*
364     * Now separate the read and write storages. jcr has no wstor...
365     *  they all go into wjcr.
366     */
367    free_rwstorage(wjcr);
368    wjcr->rstore = NULL;
369    wjcr->wstore = jcr->wstore;
370    jcr->wstore = NULL;
371    wjcr->wstorage = jcr->wstorage;
372    jcr->wstorage = NULL;
373 
374    /* TODO: See priority with bandwidth parameter */
375    if (jcr->job->max_bandwidth > 0) {
376       jcr->max_bandwidth = jcr->job->max_bandwidth;
377    } else if (jcr->client && jcr->client->max_bandwidth > 0) {
378       jcr->max_bandwidth = jcr->client->max_bandwidth;
379    }
380 
381    if (jcr->max_bandwidth > 0) {
382       send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
383    }
384 
385    /*
386     * Open a message channel connection with the Storage
387     * daemon. This is to let him know that our client
388     * will be contacting him for a backup  session.
389     *
390     */
391    jcr->setJobStatus(JS_WaitSD);
392    wjcr->setJobStatus(JS_WaitSD);
393 
394    /*
395     * Start conversation with write Storage daemon
396     */
397    Dmsg0(200, "Connect to write (wjcr) storage daemon.\n");
398    if (!connect_to_storage_daemon(wjcr, 10, SDConnectTimeout, 1)) {
399       goto bail_out;
400    }
401    wsd = wjcr->store_bsock;
402 
403    /*
404     * Start conversation with read Storage daemon
405     */
406    Dmsg1(200, "Connect to read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
407    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
408       goto bail_out;
409    }
410    sd = jcr->store_bsock;
411    if (jcr->client) {
412       jcr->sd_calls_client = jcr->client->sd_calls_client;
413    }
414 
415    Dmsg2(dbglevel, "Read store=%s, write store=%s\n",
416       ((STORE *)jcr->rstorage->first())->name(),
417       ((STORE *)wjcr->wstorage->first())->name());
418 
419    /*
420     * Now start a job with the read Storage daemon sending the bsr.
421     *  This call returns the sd_auth_key
422     */
423    Dmsg1(200, "Start job with read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
424    if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL, /*send_bsr*/true)) {
425       goto bail_out;
426    }
427    Dmsg0(150, "Read storage daemon connection OK\n");
428 
429    if (jcr->sd_calls_client) {
430       wjcr->sd_calls_client = true;
431       wjcr->sd_client = false;
432    } else {
433       wjcr->sd_calls_client = true;
434       wjcr->sd_client = true;
435    }
436 
437    /*
438     * Now start a job with the write Storage daemon sending.
439     */
440    Dmsg1(200, "Start Job with write (wjcr) storage daemon. Jid=%d\n", jcr->JobId);
441    if (!start_storage_daemon_job(wjcr, NULL, wjcr->wstorage, /*no_send_bsr*/false)) {
442       goto bail_out;
443    }
444    Dmsg0(150, "Write storage daemon connection OK\n");
445 
446 
447    /* Declare the job started to start the MaxRunTime check */
448    jcr->setJobStarted();
449 
450    /*
451     * We re-update the job start record so that the start
452     *  time is set after the run before job.  This avoids
453     *  that any files created by the run before job will
454     *  be saved twice.  They will be backed up in the current
455     *  job, but not in the next one unless they are changed.
456     *  Without this, they will be backed up in this job and
457     *  in the next job run because in that case, their date
458     *   is after the start of this run.
459     */
460    jcr->start_time = time(NULL);
461    jcr->jr.StartTime = jcr->start_time;
462    jcr->jr.JobTDate = jcr->start_time;
463    jcr->setJobStatus(JS_Running);
464 
465    /* Update job start record for this mac control job */
466    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
467       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
468       goto bail_out;
469    }
470 
471    /* Declare the job started to start the MaxRunTime check */
472    jcr->setJobStarted();
473 
474    wjcr->start_time = time(NULL);
475    wjcr->jr.StartTime = wjcr->start_time;
476    wjcr->jr.JobTDate = wjcr->start_time;
477    wjcr->setJobStatus(JS_Running);
478 
479 
480    /* Update job start record for the real mac backup job */
481    if (!db_update_job_start_record(wjcr, wjcr->db, &wjcr->jr)) {
482       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(wjcr->db));
483       goto bail_out;
484    }
485 
486    Dmsg4(dbglevel, "wjcr: Name=%s JobId=%d Type=%c Level=%c\n",
487       wjcr->jr.Name, (int)wjcr->jr.JobId,
488       wjcr->jr.JobType, wjcr->jr.JobLevel);
489 
490 
491    if (jcr->sd_calls_client) {
492       /*
493        * Reading SD must call the "client" i.e. the writing SD
494        */
495       if (jcr->SDVersion < 3) {
496          Jmsg(jcr, M_FATAL, 0, _("The Storage daemon does not support SDCallsClient.\n"));
497          goto bail_out;
498       }
499 
500       /* Setup the storage address and port */
501       store = wjcr->wstore;
502       if (store->SDDport == 0) {
503          store->SDDport = store->SDport;
504       }
505       store_address = store->address;   /* note: store points to wstore */
506 
507       Dmsg2(200, "Start write message thread jid=%d Job=%s\n", wjcr->JobId, wjcr->Job);
508       if (!run_storage_and_start_message_thread(wjcr, wsd)) {
509          goto bail_out;
510       }
511 
512       store_port = store->SDDport;
513 
514       /*
515        * Send writing SD address to the reading SD
516        */
517       /* Send and wait for connection */
518       /* ***FIXME*** this should probably be jcr->rstore, store_address, ...
519        *   to get TLS right */
520       if (!send_store_addr_to_sd(jcr, wjcr->Job, wjcr->sd_auth_key,
521            store, store_address, store_port)) {
522          goto bail_out;
523       }
524 
525       /* Start read message thread */
526       Dmsg2(200, "Start read message thread jid=%d Job=%s\n", jcr->JobId, jcr->Job);
527       if (!run_storage_and_start_message_thread(jcr, sd)) {
528          goto bail_out;
529       }
530 
531    } else {
532       /*
533        * Writing SD must simulate an FD and call the reading SD
534        *
535        * Send Storage daemon address to the writing SD
536        */
537       store = jcr->rstore;
538       if (store->SDDport == 0) {
539          store->SDDport = store->SDport;
540       }
541       store_address = get_storage_address(jcr->client, store);
542       store_port = store->SDDport;
543 
544       /* Start read message thread */
545       Dmsg2(200, "Start read message thread jid=%d Job=%s\n", jcr->JobId, jcr->Job);
546       if (!run_storage_and_start_message_thread(jcr, sd)) {
547          goto bail_out;
548       }
549 
550       /* Attempt connection for one hour */
551       if (!send_store_addr_to_sd(wjcr, jcr->Job, jcr->sd_auth_key,
552                                  store, store_address, store_port)) {
553          goto bail_out;
554       }
555       /* Start write message thread */
556       Dmsg2(200, "Start write message thread jid=%d Job=%s\n", wjcr->JobId, wjcr->Job);
557       if (!run_storage_and_start_message_thread(wjcr, wsd)) {
558          goto bail_out;
559       }
560    }
561 
562    jcr->setJobStatus(JS_Running);
563    wjcr->setJobStatus(JS_Running);
564 
565    /* Pickup Job termination data */
566    /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
567    wait_for_storage_daemon_termination(wjcr);
568    wjcr->setJobStatus(wjcr->SDJobStatus);
569    wait_for_storage_daemon_termination(jcr);
570    jcr->setJobStatus(jcr->SDJobStatus);
571 
572    flush_file_records(wjcr);     /* cached attribute + batch insert */
573 
574    ok = jcr->is_JobStatus(JS_Terminated) && wjcr->is_JobStatus(JS_Terminated);
575 
576 bail_out:
577    /* Put back jcr write storages for proper cleanup */
578    jcr->wstorage = wjcr->wstorage;
579    jcr->wstore = wjcr->wstore;
580    wjcr->wstore = NULL;
581    wjcr->wstorage = NULL;
582    wjcr->file_bsock = NULL;
583 
584    if (ok) {
585       mac_cleanup(jcr, jcr->JobStatus, wjcr->JobStatus);
586    }
587    return ok;
588 }
589 
590 /*
591  * Called from mac_sql.c for each migration/copy job to start
592  */
start_mac_job(JCR * jcr)593 void start_mac_job(JCR *jcr)
594 {
595    UAContext *ua = new_ua_context(jcr);
596    char ed1[50];
597    char args[MAX_NAME_LENGTH + 50];
598 
599    ua->batch = true;
600    Mmsg(ua->cmd, "run job=\"%s\" jobid=%s ignoreduplicatecheck=yes pool=\"%s\"",
601         jcr->job->name(), edit_uint64(jcr->MigrateJobId, ed1),
602         jcr->pool->name());
603    if (jcr->next_pool) {
604       bsnprintf(args, sizeof(args), " nextpool=\"%s\"", jcr->next_pool->name());
605       pm_strcat(ua->cmd, args);
606    }
607    Dmsg2(dbglevel, "=============== %s cmd=%s\n", jcr->get_OperationName(), ua->cmd);
608    parse_ua_args(ua);                 /* parse command */
609    JobId_t jobid = run_cmd(ua, ua->cmd);
610    if (jobid == 0) {
611       Jmsg(jcr, M_ERROR, 0, _("Could not start migration/copy job.\n"));
612    } else {
613       Jmsg(jcr, M_INFO, 0, _("%s JobId %d started.\n"), jcr->get_OperationName(), (int)jobid);
614    }
615    free_ua_context(ua);
616 }
617 
618 /*
619  * Release resources allocated during backup.
620  */
621 /* ***FIXME*** implement writeTermCode */
mac_cleanup(JCR * jcr,int TermCode,int writeTermCode)622 void mac_cleanup(JCR *jcr, int TermCode, int writeTermCode)
623 {
624    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
625    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], elapsed[50];
626    char ec6[50], ec7[50], ec8[50], ec9[30], ec10[30], edl[50];
627    char sd_term_msg[100];
628    POOL_MEM term_code;
629    POOL_MEM term_msg;
630    int msg_type = M_INFO;
631    MEDIA_DBR mr;
632    double kbps;
633    utime_t RunTime;
634    bool goterrors=false;
635    JCR *wjcr = jcr->wjcr;
636    POOL_MEM query(PM_MESSAGE);
637    POOL_MEM vol_info;
638 
639    remove_dummy_jobmedia_records(jcr);
640 
641    Dmsg2(100, "Enter mac_cleanup %d %c\n", TermCode, TermCode);
642    update_job_end(jcr, TermCode);
643 
644    /*
645     * Check if we actually did something.
646     *  wjcr is jcr of the newly migrated job.
647     */
648    if (wjcr) {
649       char old_jobid[50], new_jobid[50];
650 
651       edit_uint64(jcr->previous_jr.JobId, old_jobid);
652       edit_uint64(wjcr->jr.JobId, new_jobid);
653 
654       wjcr->JobFiles = jcr->JobFiles = wjcr->SDJobFiles;
655       wjcr->JobBytes = jcr->JobBytes = wjcr->SDJobBytes;
656       wjcr->jr.RealEndTime = 0;
657       wjcr->jr.PriorJobId = jcr->previous_jr.JobId;
658       if (jcr->previous_jr.PriorJob[0]) {
659          bstrncpy(wjcr->jr.PriorJob, jcr->previous_jr.PriorJob, sizeof(wjcr->jr.PriorJob));
660       } else {
661          bstrncpy(wjcr->jr.PriorJob, jcr->previous_jr.Job, sizeof(wjcr->jr.PriorJob));
662       }
663       wjcr->JobErrors += wjcr->SDErrors;
664       update_job_end(wjcr, TermCode);
665 
666       /* Update final items to set them to the previous job's values */
667       Mmsg(query, "UPDATE Job SET StartTime='%s',EndTime='%s',"
668                   "JobTDate=%s WHERE JobId=%s",
669          jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime,
670          edit_uint64(jcr->previous_jr.JobTDate, ec1),
671          new_jobid);
672       db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
673 
674       goterrors = jcr->SDErrors > 0 || jcr->JobErrors > 0 ||
675          jcr->SDJobStatus == JS_Canceled ||
676          jcr->SDJobStatus == JS_ErrorTerminated ||
677          jcr->SDJobStatus == JS_FatalError ||
678          jcr->JobStatus == JS_FatalError;
679 
680       if (goterrors && jcr->getJobType() == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
681          Jmsg(jcr, M_WARNING, 0, _("Found errors during the migration process. "
682                                    "The original job %s will be kept in the catalog "
683                                    "and the Migration job will be marked in Error\n"), old_jobid);
684       }
685 
686       /*
687        * If we terminated a migration normally:
688        *   - mark the previous job as migrated
689        *   - move any Log records to the new JobId
690        *   - Purge the File records from the previous job
691        */
692       if (!goterrors && jcr->getJobType() == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
693          Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
694               (char)JT_MIGRATED_JOB, old_jobid);
695          db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
696          UAContext *ua = new_ua_context(jcr);
697          /* Move JobLog to new JobId */
698          Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
699            new_jobid, old_jobid);
700          db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
701 
702          /* Move RestoreObjects */
703          Mmsg(query, "UPDATE RestoreObject SET JobId=%s WHERE JobId=%s",
704            new_jobid, old_jobid);
705          db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
706 
707          if (jcr->job->PurgeMigrateJob) {
708             /* Purge old Job record */
709             purge_jobs_from_catalog(ua, old_jobid);
710          } else {
711             /* Purge all old file records, but leave Job record */
712             purge_files_from_jobs(ua, old_jobid);
713          }
714 
715          free_ua_context(ua);
716       }
717 
718       /*
719        * If we terminated a Copy (rather than a Migration) normally:
720        *   - copy any Log records to the new JobId
721        *   - set type="Job Copy" for the new job
722        */
723       if (goterrors || (jcr->getJobType() == JT_COPY && jcr->JobStatus == JS_Terminated)) {
724          /* Copy JobLog to new JobId */
725          Mmsg(query, "INSERT INTO Log (JobId, Time, LogText ) "
726                       "SELECT %s, Time, LogText FROM Log WHERE JobId=%s",
727               new_jobid, old_jobid);
728          db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
729 
730          /* We are in a real copy job */
731          Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
732               (char)JT_JOB_COPY, new_jobid);
733          db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
734 
735          /* Copy RestoreObjects */
736          Mmsg(query, "INSERT INTO RestoreObject (ObjectName,PluginName,RestoreObject,"
737               "ObjectLength,ObjectFullLength,ObjectIndex,ObjectType,"
738               "ObjectCompression,FileIndex,JobId) "
739         "SELECT ObjectName,PluginName,RestoreObject,"
740           "ObjectLength,ObjectFullLength,ObjectIndex,ObjectType,"
741           "ObjectCompression,FileIndex,%s FROM RestoreObject WHERE JobId=%s",
742            new_jobid, old_jobid);
743          db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
744       }
745 
746       if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
747          Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
748             db_strerror(jcr->db));
749          jcr->setJobStatus(JS_ErrorTerminated);
750       }
751 
752       update_bootstrap_file(wjcr);
753 
754       if (!db_get_job_volume_names(wjcr, wjcr->db, wjcr->jr.JobId, &wjcr->VolumeName)) {
755          /*
756           * Note, if the job has failed, most likely it did not write any
757           *  tape, so suppress this "error" message since in that case
758           *  it is normal.  Or look at it the other way, only for a
759           *  normal exit should we complain about this error.
760           */
761          if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
762             Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(wjcr->db));
763          }
764          wjcr->VolumeName[0] = 0;         /* none */
765       }
766 
767       if (wjcr->VolumeName[0]) {
768          /* Find last volume name. Multiple vols are separated by | */
769          char *p = strrchr(wjcr->VolumeName, '|');
770          if (p) {
771             p++;                         /* skip | */
772          } else {
773             p = wjcr->VolumeName;     /* no |, take full name */
774          }
775          bstrncpy(mr.VolumeName, p, sizeof(mr.VolumeName));
776          if (!db_get_media_record(jcr, jcr->db, &mr)) {
777             Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
778                mr.VolumeName, db_strerror(jcr->db));
779          }
780       }
781 
782       /* We keep all information in the catalog because most of the work is
783        * done, and users might restore things from what we have
784        */
785       if (goterrors) {
786          jcr->setJobStatus(JS_ErrorTerminated);
787          Mmsg(query, "UPDATE Job SET JobStatus='%c' WHERE JobId=%s",
788               JS_ErrorTerminated, new_jobid);
789          db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
790       }
791    }
792 
793    switch (jcr->JobStatus) {
794    case JS_Terminated:
795       if (jcr->JobErrors || jcr->SDErrors) {
796          Mmsg(term_msg, _("%%s OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
797       } else {
798          Mmsg(term_msg, _("%%s OK"));
799       }
800       break;
801    case JS_FatalError:
802    case JS_ErrorTerminated:
803       Mmsg(term_msg, _("*** %%s Error ***"));
804       msg_type = M_ERROR;          /* Generate error message */
805       terminate_sd_msg_chan_thread(jcr);
806       terminate_sd_msg_chan_thread(wjcr);
807       break;
808    case JS_Canceled:
809       Mmsg(term_msg, _("%%s Canceled"));
810       terminate_sd_msg_chan_thread(jcr);
811       terminate_sd_msg_chan_thread(wjcr);
812       break;
813    default:
814       Mmsg(term_msg, _("Inappropriate %s term code"));
815       break;
816    }
817 
818    if (!wjcr) {                 /* We did nothing */
819       goterrors = jcr->JobErrors > 0 || jcr->JobStatus == JS_FatalError;
820       if (!goterrors) {
821          if (jcr->getJobType() == JT_MIGRATE && jcr->previous_jr.JobId != 0) {
822             /* Mark previous job as migrated */
823             Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
824                  (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
825             db_sql_query(jcr->db, query.c_str(), NULL, NULL);
826          }
827          Mmsg(term_msg, _("%%s -- no files to %%s"));
828       }
829    }
830 
831    Mmsg(term_code, term_msg.c_str(), jcr->get_OperationName(), jcr->get_ActionName(0));
832    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
833    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
834    RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
835    if (RunTime <= 0) {
836       RunTime = 1;
837    }
838    kbps = (double)jcr->SDJobBytes / (1000.0 * (double)RunTime);
839 
840    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
841 
842    /* Edit string for last volume size */
843    if (mr.VolABytes != 0) {
844       Mmsg(vol_info, _("meta: %s (%sB) aligned: %s (%sB)"),
845         edit_uint64_with_commas(mr.VolBytes, ec4),
846         edit_uint64_with_suffix(mr.VolBytes, ec5),
847         edit_uint64_with_commas(mr.VolABytes, ec9),
848         edit_uint64_with_suffix(mr.VolBytes, ec10));
849    } else {
850      Mmsg(vol_info, _("%s (%sB)"),
851         edit_uint64_with_commas(mr.VolBytes, ec4),
852         edit_uint64_with_suffix(mr.VolBytes, ec5));
853    }
854 
855    Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
856 "  Build OS:               %s %s %s\n"
857 "  Prev Backup JobId:      %s\n"
858 "  Prev Backup Job:        %s\n"
859 "  New Backup JobId:       %s\n"
860 "  Current JobId:          %s\n"
861 "  Current Job:            %s\n"
862 "  Backup Level:           %s%s\n"
863 "  Client:                 %s\n"
864 "  FileSet:                \"%s\" %s\n"
865 "  Read Pool:              \"%s\" (From %s)\n"
866 "  Read Storage:           \"%s\" (From %s)\n"
867 "  Write Pool:             \"%s\" (From %s)\n"
868 "  Write Storage:          \"%s\" (From %s)\n"
869 "  Catalog:                \"%s\" (From %s)\n"
870 "  Start time:             %s\n"
871 "  End time:               %s\n"
872 "  Elapsed time:           %s\n"
873 "  Priority:               %d\n"
874 "  SD Files Written:       %s\n"
875 "  SD Bytes Written:       %s (%sB)\n"
876 "  Rate:                   %.1f KB/s\n"
877 "  Volume name(s):         %s\n"
878 "  Volume Session Id:      %d\n"
879 "  Volume Session Time:    %d\n"
880 "  Last Volume Bytes:      %s\n"
881 "  SD Errors:              %d\n"
882 "  SD termination status:  %s\n"
883 "  Termination:            %s\n\n"),
884         BACULA, my_name, VERSION, LSMDATE,
885         HOST_OS, DISTNAME, DISTVER,
886         edit_uint64(jcr->previous_jr.JobId, ec6),
887         jcr->previous_jr.Job,
888         wjcr ? edit_uint64(wjcr->jr.JobId, ec7) : "0",
889         edit_uint64(jcr->jr.JobId, ec8),
890         jcr->jr.Job,
891         level_to_str(edl, sizeof(edl), jcr->getJobLevel()), jcr->since,
892         jcr->client->name(),
893         jcr->fileset->name(), jcr->FSCreateTime,
894         jcr->rpool->name(), jcr->rpool_source,
895         jcr->rstore?jcr->rstore->name():"*None*",
896         NPRT(jcr->rstore_source),
897         jcr->pool->name(), jcr->pool_source,
898         jcr->wstore?jcr->wstore->name():"*None*",
899         NPRT(jcr->wstore_source),
900         jcr->catalog->name(), jcr->catalog_source,
901         sdt,
902         edt,
903         edit_utime(RunTime, elapsed, sizeof(elapsed)),
904         jcr->JobPriority,
905         edit_uint64_with_commas(jcr->SDJobFiles, ec1),
906         edit_uint64_with_commas(jcr->SDJobBytes, ec2),
907         edit_uint64_with_suffix(jcr->SDJobBytes, ec3),
908         (float)kbps,
909         wjcr ? wjcr->VolumeName : "",
910         jcr->VolSessionId,
911         jcr->VolSessionTime,
912         vol_info.c_str(),
913         jcr->SDErrors,
914         sd_term_msg,
915         term_code.c_str());
916 
917    Dmsg0(100, "Leave migrate_cleanup()\n");
918 }
919 
set_mac_wstorage(UAContext * ua,JCR * jcr,POOL * pool,POOL * next_pool,const char * source)920 bool set_mac_wstorage(UAContext *ua, JCR *jcr, POOL *pool, POOL *next_pool,
921          const char *source)
922 {
923    if (!next_pool) {
924       if (ua) {
925          ua->error_msg(_("No Next Pool specification found in Pool \"%s\".\n"),
926            pool->hdr.name);
927       } else {
928          Jmsg(jcr, M_FATAL, 0, _("No Next Pool specification found in Pool \"%s\".\n"),
929             pool->hdr.name);
930       }
931       return false;
932    }
933 
934    if (!next_pool->storage || next_pool->storage->size() == 0) {
935       Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Next Pool \"%s\".\n"),
936          next_pool->name());
937       return false;
938    }
939 
940    /* If pool storage specified, use it instead of job storage for backup */
941    copy_wstorage(jcr, next_pool->storage, source);
942 
943    return true;
944 }
945