]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/mac.c
Fix bug #2343 where truncate of explicit Volume name truncates non-purged volumes
[bacula/bacula] / bacula / src / dird / mac.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 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  */
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->spool_data = job->spool_data;     /* turn on spooling if requested in job */
209    wjcr->spool_size = jcr->spool_size;
210    jcr->spool_size = 0;
211
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);
217
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"));
222
223       wjcr->pool = jcr->pool;
224       wjcr->next_pool = jcr->next_pool;
225       wjcr->jr.PoolId = jcr->jr.PoolId;
226    }
227
228    return true;
229 }
230
231 /*
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.
237  */
238 static bool set_mac_next_pool(JCR *jcr, POOL **retpool)
239 {
240    POOL_DBR pr;
241    POOL *pool;
242    char ed1[100];
243
244    /*
245     * Get the PoolId used with the original job. Then
246     *  find the pool name from the database record.
247     */
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));
253          return false;
254    }
255    /* Get the pool resource corresponding to the original job */
256    pool = (POOL *)GetResWithName(R_POOL, pr.Name);
257    *retpool = pool;
258    if (!pool) {
259       Jmsg(jcr, M_FATAL, 0, _("Pool resource \"%s\" not found.\n"), pr.Name);
260       return false;
261    }
262
263    if (!apply_wstorage_overrides(jcr, pool)) {
264       return false;
265    }
266
267    Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
268
269    return true;
270 }
271
272 /*
273  * Send storage address and authentication to deblock the other
274  *   job.
275  */
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)
278 {
279    int tls_need = BNET_TLS_NONE;
280
281    /* TLS Requirement */
282    if (store->tls_enable) {
283       if (store->tls_require) {
284          tls_need = BNET_TLS_REQUIRED;
285       } else {
286          tls_need = BNET_TLS_OK;
287       }
288    }
289
290    /*
291     * Send Storage address to the SD client
292     */
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);
301
302       return false;
303    }
304    return true;
305 }
306
307 /*
308  * Do a Migration and Copy of a previous job
309  *
310  *  Returns:  false on failure
311  *            true  on success
312  */
313 bool do_mac(JCR *jcr)
314 {
315    char ed1[100];
316    BSOCK *sd, *wsd;
317    JCR *wjcr = jcr->wjcr;    /* newly migrated job */
318    bool ok = false;
319    STORE *store;
320    char *store_address;
321    uint32_t store_port;
322
323    /*
324     * If wjcr is NULL, there is nothing to do for this job,
325     *  so set a normal status, cleanup and return OK.
326     */
327    if (!wjcr) {
328       jcr->setJobStatus(JS_Terminated);
329       mac_cleanup(jcr, JS_Terminated, JS_Terminated);
330       return true;
331    }
332
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);
340       return true;
341    }
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);
351       return true;
352    }
353
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);
357
358    Dmsg3(200, "Start %s JobId %s, Job=%s\n",
359         jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
360
361
362    /*
363     * Now separate the read and write storages. jcr has no wstor...
364     *  they all go into wjcr.
365     */
366    free_rwstorage(wjcr);
367    wjcr->rstore = NULL;
368    wjcr->wstore = jcr->wstore;
369    jcr->wstore = NULL;
370    wjcr->wstorage = jcr->wstorage;
371    jcr->wstorage = NULL;
372
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;
378    }
379
380    if (jcr->max_bandwidth > 0) {
381       send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
382    }
383
384    /*
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.
388     *
389     */
390    jcr->setJobStatus(JS_WaitSD);
391    wjcr->setJobStatus(JS_WaitSD);
392
393    /*
394     * Start conversation with write Storage daemon
395     */
396    Dmsg0(200, "Connect to write (wjcr) storage daemon.\n");
397    if (!connect_to_storage_daemon(wjcr, 10, SDConnectTimeout, 1)) {
398       goto bail_out;
399    }
400    wsd = wjcr->store_bsock;
401
402    /*
403     * Start conversation with read Storage daemon
404     */
405    Dmsg1(200, "Connect to read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
406    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
407       goto bail_out;
408    }
409    sd = jcr->store_bsock;
410    if (jcr->client) {
411       jcr->sd_calls_client = jcr->client->sd_calls_client;
412    }
413
414    Dmsg2(dbglevel, "Read store=%s, write store=%s\n",
415       ((STORE *)jcr->rstorage->first())->name(),
416       ((STORE *)wjcr->wstorage->first())->name());
417
418    /*
419     * Now start a job with the read Storage daemon sending the bsr.
420     *  This call returns the sd_auth_key
421     */
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)) {
424       goto bail_out;
425    }
426    Dmsg0(150, "Read storage daemon connection OK\n");
427
428    if (jcr->sd_calls_client) {
429       wjcr->sd_calls_client = true;
430       wjcr->sd_client = false;
431    } else {
432       wjcr->sd_calls_client = true;
433       wjcr->sd_client = true;
434    }
435
436    /*
437     * Now start a job with the write Storage daemon sending.
438     */
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)) {
441       goto bail_out;
442    }
443    Dmsg0(150, "Write storage daemon connection OK\n");
444
445
446    /* Declare the job started to start the MaxRunTime check */
447    jcr->setJobStarted();
448
449    /*
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.
458     */
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);
463
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));
467       goto bail_out;
468    }
469
470    /* Declare the job started to start the MaxRunTime check */
471    jcr->setJobStarted();
472
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);
477
478
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));
482       goto bail_out;
483    }
484
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);
488
489
490    if (jcr->sd_calls_client) {
491       /*
492        * Reading SD must call the "client" i.e. the writing SD
493        */
494       if (jcr->SDVersion < 3) {
495          Jmsg(jcr, M_FATAL, 0, _("The Storage daemon does not support SDCallsClient.\n"));
496          goto bail_out;
497       }
498
499       /* Setup the storage address and port */
500       store = wjcr->wstore;
501       if (store->SDDport == 0) {
502          store->SDDport = store->SDport;
503       }
504       store_address = store->address;   /* note: store points to wstore */
505
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)) {
508          goto bail_out;
509       }
510
511       store_port = store->SDDport;
512
513       /*
514        * Send writing SD address to the reading SD
515        */
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)) {
521          goto bail_out;
522       }
523
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)) {
527          goto bail_out;
528       }
529
530    } else {
531       /*
532        * Writing SD must simulate an FD and call the reading SD
533        *
534        * Send Storage daemon address to the writing SD
535        */
536       store = jcr->rstore;
537       if (store->SDDport == 0) {
538          store->SDDport = store->SDport;
539       }
540       store_address = get_storage_address(jcr->client, store);
541       store_port = store->SDDport;
542
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)) {
546          goto bail_out;
547       }
548
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)) {
552          goto bail_out;
553       }
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)) {
557          goto bail_out;
558       }
559    }
560
561    jcr->setJobStatus(JS_Running);
562    wjcr->setJobStatus(JS_Running);
563
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 */
571
572    ok = jcr->is_JobStatus(JS_Terminated) && wjcr->is_JobStatus(JS_Terminated);
573
574 bail_out:
575    /* Put back jcr write storages for proper cleanup */
576    jcr->wstorage = wjcr->wstorage;
577    jcr->wstore = wjcr->wstore;
578    wjcr->wstore = NULL;
579    wjcr->wstorage = NULL;
580    wjcr->file_bsock = NULL;
581
582    if (ok) {
583       mac_cleanup(jcr, jcr->JobStatus, wjcr->JobStatus);
584    }
585    return ok;
586 }
587
588 /*
589  * Called from mac_sql.c for each migration/copy job to start
590  */
591 void start_mac_job(JCR *jcr)
592 {
593    UAContext *ua = new_ua_context(jcr);
594    char ed1[50];
595    char args[MAX_NAME_LENGTH + 50];
596
597    ua->batch = true;
598    Mmsg(ua->cmd, "run job=\"%s\" jobid=%s ignoreduplicatecheck=yes pool=\"%s\"",
599         jcr->job->name(), edit_uint64(jcr->MigrateJobId, ed1),
600         jcr->pool->name());
601    if (jcr->next_pool) {
602       bsnprintf(args, sizeof(args), " nextpool=\"%s\"", jcr->next_pool->name());
603       pm_strcat(ua->cmd, args);
604    }
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);
608    if (jobid == 0) {
609       Jmsg(jcr, M_ERROR, 0, _("Could not start migration/copy job.\n"));
610    } else {
611       Jmsg(jcr, M_INFO, 0, _("%s JobId %d started.\n"), jcr->get_OperationName(), (int)jobid);
612    }
613    free_ua_context(ua);
614 }
615
616 /*
617  * Release resources allocated during backup.
618  */
619 /* ***FIXME*** implement writeTermCode */
620 void mac_cleanup(JCR *jcr, int TermCode, int writeTermCode)
621 {
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];
626    POOL_MEM term_code;
627    POOL_MEM term_msg;
628    int msg_type = M_INFO;
629    MEDIA_DBR mr;
630    double kbps;
631    utime_t RunTime;
632    bool goterrors=false;
633    JCR *wjcr = jcr->wjcr;
634    POOL_MEM query(PM_MESSAGE);
635    POOL_MEM vol_info;
636
637    remove_dummy_jobmedia_records(jcr);
638
639    Dmsg2(100, "Enter mac_cleanup %d %c\n", TermCode, TermCode);
640    update_job_end(jcr, TermCode);
641
642    /*
643     * Check if we actually did something.
644     *  wjcr is jcr of the newly migrated job.
645     */
646    if (wjcr) {
647       char old_jobid[50], new_jobid[50];
648
649       edit_uint64(jcr->previous_jr.JobId, old_jobid);
650       edit_uint64(wjcr->jr.JobId, new_jobid);
651
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);
658
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),
664          new_jobid);
665       db_sql_query(wjcr->db, query.c_str(), NULL, NULL);
666
667       goterrors = jcr->SDErrors > 0 || jcr->JobErrors > 0 ||
668          jcr->SDJobStatus == JS_Canceled ||
669          jcr->SDJobStatus == JS_ErrorTerminated ||
670          jcr->SDJobStatus == JS_FatalError;
671
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);
676       }
677
678       /*
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
683        */
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);
693
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);
698
699          if (jcr->job->PurgeMigrateJob) {
700             /* Purge old Job record */
701             purge_jobs_from_catalog(ua, old_jobid);
702          } else {
703             /* Purge all old file records, but leave Job record */
704             purge_files_from_jobs(ua, old_jobid);
705          }
706
707          free_ua_context(ua);
708       }
709
710       /*
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
714        */
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);
721
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);
726
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);
736       }
737
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);
742       }
743
744       update_bootstrap_file(wjcr);
745
746       if (!db_get_job_volume_names(wjcr, wjcr->db, wjcr->jr.JobId, &wjcr->VolumeName)) {
747          /*
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.
752           */
753          if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
754             Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(wjcr->db));
755          }
756          wjcr->VolumeName[0] = 0;         /* none */
757       }
758
759       if (wjcr->VolumeName[0]) {
760          /* Find last volume name. Multiple vols are separated by | */
761          char *p = strrchr(wjcr->VolumeName, '|');
762          if (p) {
763             p++;                         /* skip | */
764          } else {
765             p = wjcr->VolumeName;     /* no |, take full name */
766          }
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));
771          }
772       }
773
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
776        */
777       if (goterrors) {
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);
782       }
783
784       switch (jcr->JobStatus) {
785       case JS_Terminated:
786          if (jcr->JobErrors || jcr->SDErrors) {
787             Mmsg(term_msg, _("%%s OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
788          } else {
789             Mmsg(term_msg, _("%%s OK"));
790          }
791          break;
792       case JS_FatalError:
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);
800             }
801          }
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);
806             }
807          }
808          break;
809       case JS_Canceled:
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);
815             }
816          }
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);
821             }
822          }
823          break;
824       default:
825          Mmsg(term_msg, _("Inappropriate %s term code"));
826          break;
827       }
828    } else {
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);
834       }
835       Mmsg(term_msg, _("%%s -- no files to %%s"));
836    }
837
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;
842    if (RunTime <= 0) {
843       RunTime = 1;
844    }
845    kbps = (double)jcr->SDJobBytes / (1000.0 * (double)RunTime);
846
847    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
848
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));
856    } else {
857      Mmsg(vol_info, _("%s (%sB)"),
858         edit_uint64_with_commas(mr.VolBytes, ec4),
859         edit_uint64_with_suffix(mr.VolBytes, ec5));
860    }
861
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"
868 "  Current Job:            %s\n"
869 "  Backup Level:           %s%s\n"
870 "  Client:                 %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"
877 "  Start time:             %s\n"
878 "  End time:               %s\n"
879 "  Elapsed time:           %s\n"
880 "  Priority:               %d\n"
881 "  SD Files Written:       %s\n"
882 "  SD Bytes Written:       %s (%sB)\n"
883 "  Rate:                   %.1f KB/s\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"
888 "  SD Errors:              %d\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),
897         jcr->jr.Job,
898         level_to_str(jcr->getJobLevel()), jcr->since,
899         jcr->client->name(),
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,
908         sdt,
909         edt,
910         edit_utime(RunTime, elapsed, sizeof(elapsed)),
911         jcr->JobPriority,
912         edit_uint64_with_commas(jcr->SDJobFiles, ec1),
913         edit_uint64_with_commas(jcr->SDJobBytes, ec2),
914         edit_uint64_with_suffix(jcr->SDJobBytes, ec3),
915         (float)kbps,
916         wjcr ? wjcr->VolumeName : "",
917         jcr->VolSessionId,
918         jcr->VolSessionTime,
919         vol_info.c_str(),
920         jcr->SDErrors,
921         sd_term_msg,
922         term_code.c_str());
923
924    Dmsg0(100, "Leave migrate_cleanup()\n");
925 }
926
927 bool set_mac_wstorage(UAContext *ua, JCR *jcr, POOL *pool, POOL *next_pool,
928          const char *source)
929 {
930    if (!next_pool) {
931       if (ua) {
932          ua->error_msg(_("No Next Pool specification found in Pool \"%s\".\n"),
933            pool->hdr.name);
934       } else {
935          Jmsg(jcr, M_FATAL, 0, _("No Next Pool specification found in Pool \"%s\".\n"),
936             pool->hdr.name);
937       }
938       return false;
939    }
940
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"),
943          next_pool->name());
944       return false;
945    }
946
947    /* If pool storage specified, use it instead of job storage for backup */
948    copy_wstorage(jcr, next_pool->storage, source);
949
950    return true;
951 }