]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/mac.c
Convert a Migration job with errors into a Copy job
[bacula/bacula] / bacula / src / dird / mac.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 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  *
21  *   Bacula Director -- mac.c -- responsible for doing
22  *     migration and copy jobs.
23  *
24  *   Also handles Copy jobs (March MMVIII)
25  *
26  *   Written by Kern Sibbald, September MMIV
27  *
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
32  *       to do the backup.
33  *     When the Storage daemon finishes the job, update the DB.
34  *
35  */
36
37 #include "bacula.h"
38 #include "dird.h"
39 #include "ua.h"
40
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";
44
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,
50                  const char *type);
51 extern bool find_jobids_of_pool_uncopied_jobs(JCR *jcr, idpkt *ids);
52
53 static bool set_mac_next_pool(JCR *jcr, POOL **pool);
54
55 /*
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.
64  *
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
73  *    job.
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).
82  */
83 bool do_mac_init(JCR *jcr)
84 {
85    POOL *pool = NULL;
86    JOB *job, *prev_job;
87    JCR *wjcr;                     /* jcr of writing job */
88    int count;
89
90
91    apply_pool_overrides(jcr);
92
93    if (!allow_duplicate_job(jcr)) {
94       return false;
95    }
96
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"));
101       return false;
102    }
103    /*
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.
108     */
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);
112
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"));
116       return false;
117    }
118
119    /* If we find a job or jobs to migrate it is previous_jr.JobId */
120    count = getJob_to_migrate(jcr);
121    if (count < 0) {
122       return false;
123    }
124    if (count == 0) {
125       set_mac_next_pool(jcr, &pool);
126       return true;                    /* no work */
127    }
128
129    Dmsg1(dbglevel, "Back from getJob_to_migrate JobId=%d\n", (int)jcr->JobId);
130
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 */
136    }
137
138    if (create_restore_bootstrap_file(jcr) < 0) {
139       Jmsg(jcr, M_FATAL, 0, _("Create bootstrap file failed.\n"));
140       return false;
141    }
142
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));
148       } else {
149          Jmsg(jcr, M_INFO, 0, _("Previous Job has no data to %s.\n"), jcr->get_ActionName(0));
150       }
151       set_mac_next_pool(jcr, &pool);
152       return true;                    /* no work */
153    }
154
155
156    Dmsg5(dbglevel, "JobId=%d: Current: Name=%s JobId=%d Type=%c Level=%c\n",
157       (int)jcr->JobId,
158       jcr->jr.Name, (int)jcr->jr.JobId,
159       jcr->jr.JobType, jcr->jr.JobLevel);
160
161    LockRes();
162    job = (JOB *)GetResWithName(R_JOB, jcr->jr.Name);
163    prev_job = (JOB *)GetResWithName(R_JOB, jcr->previous_jr.Name);
164    UnlockRes();
165    if (!job) {
166       Jmsg(jcr, M_FATAL, 0, _("Job resource not found for \"%s\".\n"), jcr->jr.Name);
167       return false;
168    }
169    if (!prev_job) {
170       Jmsg(jcr, M_FATAL, 0, _("Previous Job resource not found for \"%s\".\n"),
171            jcr->previous_jr.Name);
172       return false;
173    }
174
175
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));
179
180    /*
181     * Turn the wjcr into a "real" job that takes on the aspects of
182     *   the previous backup job "prev_job".
183     */
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
188     */
189    if (wjcr->getJobLevel() == L_VIRTUAL_FULL) {
190       wjcr->setJobLevel(L_INCREMENTAL);
191    }
192    if (!setup_job(wjcr)) {
193       Jmsg(jcr, M_FATAL, 0, _("setup job failed.\n"));
194       return false;
195    }
196
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;
206    jcr->spool_size = 0;
207
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);
215
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"));
220
221       wjcr->pool = jcr->pool;
222       wjcr->next_pool = jcr->next_pool;
223       wjcr->jr.PoolId = jcr->jr.PoolId;
224    }
225
226    return true;
227 }
228
229 /*
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.
235  */
236 static bool set_mac_next_pool(JCR *jcr, POOL **retpool)
237 {
238    POOL_DBR pr;
239    POOL *pool;
240    char ed1[100];
241
242    /*
243     * Get the PoolId used with the original job. Then
244     *  find the pool name from the database record.
245     */
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));
251          return false;
252    }
253    /* Get the pool resource corresponding to the original job */
254    pool = (POOL *)GetResWithName(R_POOL, pr.Name);
255    *retpool = pool;
256    if (!pool) {
257       Jmsg(jcr, M_FATAL, 0, _("Pool resource \"%s\" not found.\n"), pr.Name);
258       return false;
259    }
260
261    if (!apply_wstorage_overrides(jcr, pool)) {
262       return false;
263    }
264
265    Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
266
267    return true;
268 }
269
270 /*
271  * Send storage address and authentication to deblock the other
272  *   job.
273  */
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)
276 {
277    int tls_need = BNET_TLS_NONE;
278
279    /* TLS Requirement */
280    if (store->tls_enable) {
281       if (store->tls_require) {
282          tls_need = BNET_TLS_REQUIRED;
283       } else {
284          tls_need = BNET_TLS_OK;
285       }
286    }
287
288    /*
289     * Send Storage address to the SD client
290     */
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);
299
300       return false;
301    }
302    return true;
303 }
304
305 /*
306  * Do a Migration and Copy of a previous job
307  *
308  *  Returns:  false on failure
309  *            true  on success
310  */
311 bool do_mac(JCR *jcr)
312 {
313    char ed1[100];
314    BSOCK *sd, *wsd;
315    JCR *wjcr = jcr->wjcr;    /* newly migrated job */
316    bool ok = false;
317    STORE *store;
318    char *store_address;
319    uint32_t store_port;
320
321    /*
322     * If wjcr is NULL, there is nothing to do for this job,
323     *  so set a normal status, cleanup and return OK.
324     */
325    if (!wjcr) {
326       jcr->setJobStatus(JS_Terminated);
327       mac_cleanup(jcr, JS_Terminated, JS_Terminated);
328       return true;
329    }
330
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);
338       return true;
339    }
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);
349       return true;
350    }
351
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);
355
356    Dmsg3(200, "Start %s JobId %s, Job=%s\n",
357         jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
358
359
360    /*
361     * Now separate the read and write storages. jcr has no wstor...
362     *  they all go into wjcr.
363     */
364    free_rwstorage(wjcr);
365    wjcr->rstore = NULL;
366    wjcr->wstore = jcr->wstore;
367    jcr->wstore = NULL;
368    wjcr->wstorage = jcr->wstorage;
369    jcr->wstorage = NULL;
370
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;
376    }
377
378    if (jcr->max_bandwidth > 0) {
379       send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
380    }
381
382    /*
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.
386     *
387     */
388    jcr->setJobStatus(JS_WaitSD);
389    wjcr->setJobStatus(JS_WaitSD);
390
391    /*
392     * Start conversation with write Storage daemon
393     */
394    Dmsg0(200, "Connect to write (wjcr) storage daemon.\n");
395    if (!connect_to_storage_daemon(wjcr, 10, SDConnectTimeout, 1)) {
396       goto bail_out;
397    }
398    wsd = wjcr->store_bsock;
399
400    /*
401     * Start conversation with read Storage daemon
402     */
403    Dmsg1(200, "Connect to read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
404    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
405       goto bail_out;
406    }
407    sd = jcr->store_bsock;
408    if (jcr->client) {
409       jcr->sd_calls_client = jcr->client->sd_calls_client;
410    }
411
412    Dmsg2(dbglevel, "Read store=%s, write store=%s\n",
413       ((STORE *)jcr->rstorage->first())->name(),
414       ((STORE *)wjcr->wstorage->first())->name());
415
416    /*
417     * Now start a job with the read Storage daemon sending the bsr.
418     *  This call returns the sd_auth_key
419     */
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)) {
422       goto bail_out;
423    }
424    Dmsg0(150, "Read storage daemon connection OK\n");
425
426    if (jcr->sd_calls_client) {
427       wjcr->sd_calls_client = true;
428       wjcr->sd_client = false;
429    } else {
430       wjcr->sd_calls_client = true;
431       wjcr->sd_client = true;
432    }
433
434    /*
435     * Now start a job with the write Storage daemon sending.
436     */
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)) {
439       goto bail_out;
440    }
441    Dmsg0(150, "Write storage daemon connection OK\n");
442
443
444    /* Declare the job started to start the MaxRunTime check */
445    jcr->setJobStarted();
446
447    /*
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.
456     */
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);
461
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));
465       goto bail_out;
466    }
467
468    /* Declare the job started to start the MaxRunTime check */
469    jcr->setJobStarted();
470
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);
475
476
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));
480       goto bail_out;
481    }
482
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);
486
487
488    if (jcr->sd_calls_client) {
489       /*
490        * Reading SD must call the "client" i.e. the writing SD
491        */
492       if (jcr->SDVersion < 3) {
493          Jmsg(jcr, M_FATAL, 0, _("The Storage daemon does not support SDCallsClient.\n"));
494          goto bail_out;
495       }
496
497       /* Setup the storage address and port */
498       store = wjcr->wstore;
499       if (store->SDDport == 0) {
500          store->SDDport = store->SDport;
501       }
502       store_address = store->address;   /* note: store points to wstore */
503
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)) {
506          goto bail_out;
507       }
508
509       store_port = store->SDDport;
510
511       /*
512        * Send writing SD address to the reading SD
513        */
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)) {
519          goto bail_out;
520       }
521
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)) {
525          goto bail_out;
526       }
527
528    } else {
529       /*
530        * Writing SD must simulate an FD and call the reading SD
531        *
532        * Send Storage daemon address to the writing SD
533        */
534       store = jcr->rstore;
535       if (store->SDDport == 0) {
536          store->SDDport = store->SDport;
537       }
538       store_address = get_storage_address(jcr->client, store);
539       store_port = store->SDDport;
540
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)) {
544          goto bail_out;
545       }
546
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)) {
550          goto bail_out;
551       }
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)) {
555          goto bail_out;
556       }
557    }
558
559    jcr->setJobStatus(JS_Running);
560    wjcr->setJobStatus(JS_Running);
561
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 */
569
570    ok = jcr->is_JobStatus(JS_Terminated) && wjcr->is_JobStatus(JS_Terminated);
571
572 bail_out:
573    /* Put back jcr write storages for proper cleanup */
574    jcr->wstorage = wjcr->wstorage;
575    jcr->wstore = wjcr->wstore;
576    wjcr->wstore = NULL;
577    wjcr->wstorage = NULL;
578    wjcr->file_bsock = NULL;
579
580    if (ok) {
581       mac_cleanup(jcr, jcr->JobStatus, wjcr->JobStatus);
582    }
583    return ok;
584 }
585
586 /*
587  * Called from mac_sql.c for each migration/copy job to start
588  */
589 void start_mac_job(JCR *jcr)
590 {
591    UAContext *ua = new_ua_context(jcr);
592    char ed1[50];
593    char args[MAX_NAME_LENGTH + 50];
594
595    ua->batch = true;
596    Mmsg(ua->cmd, "run job=\"%s\" jobid=%s ignoreduplicatecheck=yes pool=\"%s\"",
597         jcr->job->name(), edit_uint64(jcr->MigrateJobId, ed1),
598         jcr->pool->name());
599    if (jcr->next_pool) {
600       bsnprintf(args, sizeof(args), " nextpool=\"%s\"", jcr->next_pool->name());
601       pm_strcat(ua->cmd, args);
602    }
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);
606    if (jobid == 0) {
607       Jmsg(jcr, M_ERROR, 0, _("Could not start migration/copy job.\n"));
608    } else {
609       Jmsg(jcr, M_INFO, 0, _("%s JobId %d started.\n"), jcr->get_OperationName(), (int)jobid);
610    }
611    free_ua_context(ua);
612 }
613
614 /*
615  * Release resources allocated during backup.
616  */
617 /* ***FIXME*** implement writeTermCode */
618 void mac_cleanup(JCR *jcr, int TermCode, int writeTermCode)
619 {
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;
626    MEDIA_DBR mr;
627    double kbps;
628    utime_t RunTime;
629    bool goterrors=false;
630    JCR *wjcr = jcr->wjcr;
631    POOL_MEM query(PM_MESSAGE);
632    POOL_MEM vol_info;
633
634    Dmsg2(100, "Enter mac_cleanup %d %c\n", TermCode, TermCode);
635    update_job_end(jcr, TermCode);
636
637    /*
638     * Check if we actually did something.
639     *  wjcr is jcr of the newly migrated job.
640     */
641    if (wjcr) {
642       char old_jobid[50], new_jobid[50];
643
644       edit_uint64(jcr->previous_jr.JobId, old_jobid);
645       edit_uint64(wjcr->jr.JobId, new_jobid);
646
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;
651
652       update_job_end(wjcr, TermCode);
653
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),
659          new_jobid);
660       db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
661
662       goterrors = jcr->SDErrors > 0 || jcr->JobErrors > 0 ||
663          jcr->SDJobStatus == JS_Canceled ||
664          jcr->SDJobStatus == JS_ErrorTerminated ||
665          jcr->SDJobStatus == JS_FatalError;
666
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);
671       }
672
673       /*
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
678        */
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);
688
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);
693
694          if (jcr->job->PurgeMigrateJob) {
695             /* Purge old Job record */
696             purge_jobs_from_catalog(ua, old_jobid);
697          } else {
698             /* Purge all old file records, but leave Job record */
699             purge_files_from_jobs(ua, old_jobid);
700          }
701
702          free_ua_context(ua);
703       }
704
705       /*
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
709        */
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);
716
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);
721
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);
731       }
732
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);
737       }
738
739       update_bootstrap_file(wjcr);
740
741       if (!db_get_job_volume_names(wjcr, wjcr->db, wjcr->jr.JobId, &wjcr->VolumeName)) {
742          /*
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.
747           */
748          if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
749             Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(wjcr->db));
750          }
751          wjcr->VolumeName[0] = 0;         /* none */
752       }
753
754       if (wjcr->VolumeName[0]) {
755          /* Find last volume name. Multiple vols are separated by | */
756          char *p = strrchr(wjcr->VolumeName, '|');
757          if (p) {
758             p++;                         /* skip | */
759          } else {
760             p = wjcr->VolumeName;     /* no |, take full name */
761          }
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));
766          }
767       }
768
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
771        */
772       if (goterrors) {
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);
777       }
778
779       switch (jcr->JobStatus) {
780       case JS_Terminated:
781          if (jcr->JobErrors || jcr->SDErrors) {
782             term_msg = _("%s OK -- with warnings");
783          } else {
784             term_msg = _("%s OK");
785          }
786          break;
787       case JS_FatalError:
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);
795             }
796          }
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);
801             }
802          }
803          break;
804       case JS_Canceled:
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);
810             }
811          }
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);
816             }
817          }
818          break;
819       default:
820          term_msg = _("Inappropriate %s term code");
821          break;
822       }
823    } else {
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);
829       }
830       term_msg = _("%s -- no files to %s");
831    }
832
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;
837    if (RunTime <= 0) {
838       kbps = 0;
839    } else {
840       kbps = (double)jcr->SDJobBytes / (1000 * RunTime);
841    }
842
843    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
844
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));
852    } else {
853      Mmsg(vol_info, _("%s (%sB)"),
854         edit_uint64_with_commas(mr.VolBytes, ec4),
855         edit_uint64_with_suffix(mr.VolBytes, ec5));
856    }
857
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"
864 "  Current Job:            %s\n"
865 "  Backup Level:           %s%s\n"
866 "  Client:                 %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"
873 "  Start time:             %s\n"
874 "  End time:               %s\n"
875 "  Elapsed time:           %s\n"
876 "  Priority:               %d\n"
877 "  SD Files Written:       %s\n"
878 "  SD Bytes Written:       %s (%sB)\n"
879 "  Rate:                   %.1f KB/s\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"
884 "  SD Errors:              %d\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),
893         jcr->jr.Job,
894         level_to_str(jcr->getJobLevel()), jcr->since,
895         jcr->client->name(),
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,
904         sdt,
905         edt,
906         edit_utime(RunTime, elapsed, sizeof(elapsed)),
907         jcr->JobPriority,
908         edit_uint64_with_commas(jcr->SDJobFiles, ec1),
909         edit_uint64_with_commas(jcr->SDJobBytes, ec2),
910         edit_uint64_with_suffix(jcr->SDJobBytes, ec3),
911         (float)kbps,
912         wjcr ? wjcr->VolumeName : "",
913         jcr->VolSessionId,
914         jcr->VolSessionTime,
915         vol_info.c_str(),
916         jcr->SDErrors,
917         sd_term_msg,
918         term_code);
919
920    Dmsg0(100, "Leave migrate_cleanup()\n");
921 }
922
923 bool set_mac_wstorage(UAContext *ua, JCR *jcr, POOL *pool, POOL *next_pool,
924          const char *source)
925 {
926    if (!next_pool) {
927       if (ua) {
928          ua->error_msg(_("No Next Pool specification found in Pool \"%s\".\n"),
929            pool->hdr.name);
930       } else {
931          Jmsg(jcr, M_FATAL, 0, _("No Next Pool specification found in Pool \"%s\".\n"),
932             pool->hdr.name);
933       }
934       return false;
935    }
936
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"),
939          next_pool->name());
940       return false;
941    }
942
943    /* If pool storage specified, use it instead of job storage for backup */
944    copy_wstorage(jcr, next_pool->storage, source);
945
946    return true;
947 }