]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/migrate.c
Fix seg fault in plugin event loop
[bacula/bacula] / bacula / src / dird / migrate.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   Bacula Director -- migrate.c -- responsible for doing
31  *     migration and copy jobs.
32  * 
33  *   Also handles Copy jobs (March MMVIII)
34  *
35  *     Kern Sibbald, September MMIV
36  *
37  *  Basic tasks done here:
38  *     Open DB and create records for this job.
39  *     Open Message Channel with Storage daemon to tell him a job will be starting.
40  *     Open connection with Storage daemon and pass him commands
41  *       to do the backup.
42  *     When the Storage daemon finishes the job, update the DB.
43  *
44  */
45
46 #include "bacula.h"
47 #include "dird.h"
48 #include "ua.h"
49 #ifndef HAVE_REGEX_H
50 #include "lib/bregex.h"
51 #else
52 #include <regex.h>
53 #endif
54
55 static const int dbglevel = 10;
56
57 static int getJob_to_migrate(JCR *jcr);
58 struct idpkt;
59 static bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1,
60                  const char *query2, const char *type);
61 static bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1,
62                  const char *type);
63 static bool find_jobids_from_mediaid_list(JCR *jcr, idpkt *ids, const char *type);
64 static bool find_jobids_of_pool_uncopied_jobs(JCR *jcr, idpkt *ids);
65 static void start_migration_job(JCR *jcr);
66 static int get_next_dbid_from_list(char **p, DBId_t *DBId);
67 static bool set_migration_next_pool(JCR *jcr, POOL **pool);
68
69 /* 
70  * Called here before the job is run to do the job
71  *   specific setup.  Note, one of the important things to
72  *   complete in this init code is to make the definitive
73  *   choice of input and output storage devices.  This is
74  *   because immediately after the init, the job is queued
75  *   in the jobq.c code, and it checks that all the resources
76  *   (storage resources in particular) are available, so these
77  *   must all be properly defined.
78  *
79  *  previous_jr refers to the job DB record of the Job that is
80  *    going to be migrated.
81  *  prev_job refers to the job resource of the Job that is
82  *    going to be migrated.
83  *  jcr is the jcr for the current "migration" job.  It is a
84  *    control job that is put in the DB as a migration job, which
85  *    means that this job migrated a previous job to a new job.
86  *    No Volume or File data is associated with this control
87  *    job.
88  *  mig_jcr refers to the newly migrated job that is run by
89  *    the current jcr.  It is a backup job that moves (migrates) the
90  *    data written for the previous_jr into the new pool.  This
91  *    job (mig_jcr) becomes the new backup job that replaces
92  *    the original backup job. Note, this jcr is not really run. It
93  *    is simply attached to the current jcr.  It will show up in
94  *    the Director's status output, but not in the SD or FD, both of
95  *    which deal only with the current migration job (i.e. jcr).
96  */
97 bool do_migration_init(JCR *jcr)
98 {
99    POOL *pool = NULL;
100    JOB *job, *prev_job;
101    JCR *mig_jcr;                   /* newly migrated job */
102    int count;
103
104
105    apply_pool_overrides(jcr);
106
107    if (!allow_duplicate_job(jcr)) {
108       return false;
109    }
110
111    jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
112    if (jcr->jr.PoolId == 0) {
113       Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId);
114       Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
115       return false;
116    }
117    /*
118     * Note, at this point, pool is the pool for this job.  We
119     *  transfer it to rpool (read pool), and a bit later,
120     *  pool will be changed to point to the write pool, 
121     *  which comes from pool->NextPool.
122     */
123    jcr->rpool = jcr->pool;            /* save read pool */
124    pm_strcpy(jcr->rpool_source, jcr->pool_source);
125
126
127    Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
128
129    if (!get_or_create_fileset_record(jcr)) {
130       Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
131       Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
132       return false;
133    }
134
135    /* If we find a job or jobs to migrate it is previous_jr.JobId */
136    count = getJob_to_migrate(jcr);
137    if (count < 0) {
138       return false;
139    }
140    if (count == 0) {
141       set_migration_next_pool(jcr, &pool);
142       return true;                    /* no work */
143    }
144
145    Dmsg1(dbglevel, "Back from getJob_to_migrate JobId=%d\n", (int)jcr->JobId);
146
147    if (jcr->previous_jr.JobId == 0) {
148       Dmsg1(dbglevel, "JobId=%d no previous JobId\n", (int)jcr->JobId);
149       Jmsg(jcr, M_INFO, 0, _("No previous Job found to %s.\n"), jcr->get_ActionName(0));
150       set_migration_next_pool(jcr, &pool);
151       return true;                    /* no work */
152    }
153
154    if (create_restore_bootstrap_file(jcr) < 0) {
155       Jmsg(jcr, M_FATAL, 0, _("Create bootstrap file failed.\n"));
156       return false;
157    }
158
159    if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) {
160       jcr->setJobStatus(JS_Terminated);
161       Dmsg1(dbglevel, "JobId=%d expected files == 0\n", (int)jcr->JobId);
162       if (jcr->previous_jr.JobId == 0) {
163          Jmsg(jcr, M_INFO, 0, _("No previous Job found to %s.\n"), jcr->get_ActionName(0));
164       } else {
165          Jmsg(jcr, M_INFO, 0, _("Previous Job has no data to %s.\n"), jcr->get_ActionName(0));
166       }
167       set_migration_next_pool(jcr, &pool);
168       return true;                    /* no work */
169    }
170
171
172    Dmsg5(dbglevel, "JobId=%d: Current: Name=%s JobId=%d Type=%c Level=%c\n",
173       (int)jcr->JobId,
174       jcr->jr.Name, (int)jcr->jr.JobId, 
175       jcr->jr.JobType, jcr->jr.JobLevel);
176
177    LockRes();
178    job = (JOB *)GetResWithName(R_JOB, jcr->jr.Name);
179    prev_job = (JOB *)GetResWithName(R_JOB, jcr->previous_jr.Name);
180    UnlockRes();
181    if (!job) {
182       Jmsg(jcr, M_FATAL, 0, _("Job resource not found for \"%s\".\n"), jcr->jr.Name);
183       return false;
184    }
185    if (!prev_job) {
186       Jmsg(jcr, M_FATAL, 0, _("Previous Job resource not found for \"%s\".\n"), 
187            jcr->previous_jr.Name);
188       return false;
189    }
190
191    jcr->spool_data = job->spool_data;     /* turn on spooling if requested in job */ 
192
193    /* Create a migration jcr */
194    mig_jcr = jcr->mig_jcr = new_jcr(sizeof(JCR), dird_free_jcr);
195    memcpy(&mig_jcr->previous_jr, &jcr->previous_jr, sizeof(mig_jcr->previous_jr));
196
197    /*
198     * Turn the mig_jcr into a "real" job that takes on the aspects of
199     *   the previous backup job "prev_job".
200     */
201    set_jcr_defaults(mig_jcr, prev_job);
202    if (!setup_job(mig_jcr)) {
203       Jmsg(jcr, M_FATAL, 0, _("setup job failed.\n"));
204       return false;
205    }
206
207    /* Now reset the job record from the previous job */
208    memcpy(&mig_jcr->jr, &jcr->previous_jr, sizeof(mig_jcr->jr));
209    /* Update the jr to reflect the new values of PoolId and JobId. */
210    mig_jcr->jr.PoolId = jcr->jr.PoolId;
211    mig_jcr->jr.JobId = mig_jcr->JobId;
212
213    /* Don't let WatchDog checks Max*Time value on this Job */
214    mig_jcr->no_maxtime = true;
215
216    /*
217     * Don't check for duplicates on migration and copy jobs
218     */
219    mig_jcr->job->IgnoreDuplicateJobChecking = true;
220
221    Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n",
222       mig_jcr->jr.Name, (int)mig_jcr->jr.JobId, 
223       mig_jcr->jr.JobType, mig_jcr->jr.JobLevel);
224
225    if (set_migration_next_pool(jcr, &pool)) {
226       /* If pool storage specified, use it for restore */
227       copy_rstorage(mig_jcr, pool->storage, _("Pool resource"));
228       copy_rstorage(jcr, pool->storage, _("Pool resource"));
229
230       mig_jcr->pool = jcr->pool;
231       mig_jcr->jr.PoolId = jcr->jr.PoolId;
232    }
233
234    return true;
235 }
236
237
238 /*
239  * set_migration_next_pool() called by do_migration_init()
240  * at differents stages.
241  * The  idea here is to make a common subroutine for the 
242  *   NextPool's search code and to permit do_migration_init() 
243  *   to return with NextPool set in jcr struct.
244  */
245 static bool set_migration_next_pool(JCR *jcr, POOL **retpool)
246 {
247    POOL_DBR pr;
248    POOL *pool;
249    char ed1[100];
250
251    /*
252     * Get the PoolId used with the original job. Then
253     *  find the pool name from the database record.
254     */
255    memset(&pr, 0, sizeof(pr));
256    pr.PoolId = jcr->jr.PoolId;
257    if (!db_get_pool_record(jcr, jcr->db, &pr)) {
258       Jmsg(jcr, M_FATAL, 0, _("Pool for JobId %s not in database. ERR=%s\n"),
259             edit_int64(pr.PoolId, ed1), db_strerror(jcr->db));
260          return false;
261    }
262    /* Get the pool resource corresponding to the original job */
263    pool = (POOL *)GetResWithName(R_POOL, pr.Name);
264    *retpool = pool;
265    if (!pool) {
266       Jmsg(jcr, M_FATAL, 0, _("Pool resource \"%s\" not found.\n"), pr.Name);
267       return false;
268    }
269
270    /*
271     * If the original backup pool has a NextPool, make sure a 
272     *  record exists in the database. Note, in this case, we
273     *  will be migrating from pool to pool->NextPool.
274     */
275    if (pool->NextPool) {
276       jcr->jr.PoolId = get_or_create_pool_record(jcr, pool->NextPool->name());
277       if (jcr->jr.PoolId == 0) {
278          return false;
279       }
280    }
281    if (!set_migration_wstorage(jcr, pool)) {
282       return false;
283    }
284    jcr->pool = pool->NextPool;
285    pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
286
287    Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
288
289    return true;
290 }
291
292
293 /*
294  * Do a Migration of a previous job
295  *
296  *  Returns:  false on failure
297  *            true  on success
298  */
299 bool do_migration(JCR *jcr)
300 {
301    char ed1[100];
302    BSOCK *sd;
303    JCR *mig_jcr = jcr->mig_jcr;    /* newly migrated job */
304
305    /*
306     * If mig_jcr is NULL, there is nothing to do for this job,
307     *  so set a normal status, cleanup and return OK.
308     */
309    if (!mig_jcr) {
310       jcr->setJobStatus(JS_Terminated);
311       migration_cleanup(jcr, jcr->JobStatus);
312       return true;
313    }
314
315    if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
316       Jmsg(jcr, M_FATAL, 0, _("Could not get job record for JobId %s to %s. ERR=%s"),
317            edit_int64(jcr->previous_jr.JobId, ed1),
318            jcr->get_ActionName(0),
319            db_strerror(jcr->db));
320       jcr->setJobStatus(JS_Terminated);
321       migration_cleanup(jcr, jcr->JobStatus);
322       return true;
323    }
324    /* Make sure this job was not already migrated */
325    if (jcr->previous_jr.JobType != JT_BACKUP &&
326        jcr->previous_jr.JobType != JT_JOB_COPY) {
327       Jmsg(jcr, M_INFO, 0, _("JobId %s already %s probably by another Job. %s stopped.\n"),
328          edit_int64(jcr->previous_jr.JobId, ed1),
329          jcr->get_ActionName(1),
330          jcr->get_OperationName());
331       jcr->setJobStatus(JS_Terminated);
332       migration_cleanup(jcr, jcr->JobStatus);
333       return true;
334    }
335
336    /* Print Job Start message */
337    Jmsg(jcr, M_INFO, 0, _("Start %s JobId %s, Job=%s\n"),
338         jcr->get_OperationName(), edit_uint64(jcr->JobId, ed1), jcr->Job);
339
340    /*
341     * Open a message channel connection with the Storage
342     * daemon. This is to let him know that our client
343     * will be contacting him for a backup  session.
344     *
345     */
346    Dmsg0(110, "Open connection with storage daemon\n");
347    jcr->setJobStatus(JS_WaitSD);
348    mig_jcr->setJobStatus(JS_WaitSD);
349    /*
350     * Start conversation with Storage daemon
351     */
352    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
353       return false;
354    }
355    sd = jcr->store_bsock;
356    /*
357     * Now start a job with the Storage daemon
358     */
359    Dmsg2(dbglevel, "Read store=%s, write store=%s\n", 
360       ((STORE *)jcr->rstorage->first())->name(),
361       ((STORE *)jcr->wstorage->first())->name());
362
363    if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage, /*send_bsr*/true)) {
364       return false;
365    }
366    Dmsg0(150, "Storage daemon connection OK\n");
367
368
369    /*    
370     * We re-update the job start record so that the start
371     *  time is set after the run before job.  This avoids 
372     *  that any files created by the run before job will
373     *  be saved twice.  They will be backed up in the current
374     *  job, but not in the next one unless they are changed.
375     *  Without this, they will be backed up in this job and
376     *  in the next job run because in that case, their date 
377     *   is after the start of this run.
378     */
379    jcr->start_time = time(NULL);
380    jcr->jr.StartTime = jcr->start_time;
381    jcr->jr.JobTDate = jcr->start_time;
382    jcr->setJobStatus(JS_Running);
383
384    /* Update job start record for this migration control job */
385    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
386       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
387       return false;
388    }
389
390
391    mig_jcr->start_time = time(NULL);
392    mig_jcr->jr.StartTime = mig_jcr->start_time;
393    mig_jcr->jr.JobTDate = mig_jcr->start_time;
394    mig_jcr->setJobStatus(JS_Running);
395
396    /* Update job start record for the real migration backup job */
397    if (!db_update_job_start_record(mig_jcr, mig_jcr->db, &mig_jcr->jr)) {
398       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(mig_jcr->db));
399       return false;
400    }
401
402    Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n",
403       mig_jcr->jr.Name, (int)mig_jcr->jr.JobId, 
404       mig_jcr->jr.JobType, mig_jcr->jr.JobLevel);
405
406
407    /*
408     * Start the job prior to starting the message thread below
409     * to avoid two threads from using the BSOCK structure at
410     * the same time.
411     */
412    if (!sd->fsend("run")) {
413       return false;
414    }
415
416    /*
417     * Now start a Storage daemon message thread
418     */
419    if (!start_storage_daemon_message_thread(jcr)) {
420       return false;
421    }
422
423
424    jcr->setJobStatus(JS_Running);
425    mig_jcr->setJobStatus(JS_Running);
426
427    /* Pickup Job termination data */
428    /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
429    wait_for_storage_daemon_termination(jcr);
430    jcr->setJobStatus(jcr->SDJobStatus);
431    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
432    if (jcr->JobStatus != JS_Terminated) {
433       return false;
434    }
435
436    migration_cleanup(jcr, jcr->JobStatus);
437
438    return true;
439 }
440
441 struct idpkt {
442    POOLMEM *list;
443    uint32_t count;
444 };
445
446 /* Add an item to the list if it is unique */
447 static void add_unique_id(idpkt *ids, char *item) 
448 {
449    const int maxlen = 30;
450    char id[maxlen+1];
451    char *q = ids->list;
452
453    /* Walk through current list to see if each item is the same as item */
454    for ( ; *q; ) {
455        id[0] = 0;
456        for (int i=0; i<maxlen; i++) {
457           if (*q == 0) {
458              break;
459           } else if (*q == ',') {
460              q++;
461              break;
462           }
463           id[i] = *q++;
464           id[i+1] = 0;
465        }
466        if (strcmp(item, id) == 0) {
467           return;
468        }
469    }
470    /* Did not find item, so add it to list */
471    if (ids->count == 0) {
472       ids->list[0] = 0;
473    } else {
474       pm_strcat(ids->list, ",");
475    }
476    pm_strcat(ids->list, item);
477    ids->count++;
478 // Dmsg3(0, "add_uniq count=%d Ids=%p %s\n", ids->count, ids->list, ids->list);
479    return;
480 }
481
482 /*
483  * Callback handler make list of DB Ids
484  */
485 static int unique_dbid_handler(void *ctx, int num_fields, char **row)
486 {
487    idpkt *ids = (idpkt *)ctx;
488
489    /* Sanity check */
490    if (!row || !row[0]) {
491       Dmsg0(dbglevel, "dbid_hdlr error empty row\n");
492       return 1;              /* stop calling us */
493    }
494
495    add_unique_id(ids, row[0]);
496    Dmsg3(dbglevel, "dbid_hdlr count=%d Ids=%p %s\n", ids->count, ids->list, ids->list);
497    return 0;
498 }
499
500
501 struct uitem {
502    dlink link;   
503    char *item;
504 };
505
506 static int item_compare(void *item1, void *item2)
507 {
508    uitem *i1 = (uitem *)item1;
509    uitem *i2 = (uitem *)item2;
510    return strcmp(i1->item, i2->item);
511 }
512
513 static int unique_name_handler(void *ctx, int num_fields, char **row)
514 {
515    dlist *list = (dlist *)ctx;
516
517    uitem *new_item = (uitem *)malloc(sizeof(uitem));
518    uitem *item;
519    
520    memset(new_item, 0, sizeof(uitem));
521    new_item->item = bstrdup(row[0]);
522    Dmsg1(dbglevel, "Unique_name_hdlr Item=%s\n", row[0]);
523    item = (uitem *)list->binary_insert((void *)new_item, item_compare);
524    if (item != new_item) {            /* already in list */
525       free(new_item->item);
526       free((char *)new_item);
527       return 0;
528    }
529    return 0;
530 }
531
532 /* Get Job names in Pool */
533 const char *sql_job =
534    "SELECT DISTINCT Job.Name from Job,Pool"
535    " WHERE Pool.Name='%s' AND Job.PoolId=Pool.PoolId";
536
537 /* Get JobIds from regex'ed Job names */
538 const char *sql_jobids_from_job =
539    "SELECT DISTINCT Job.JobId,Job.StartTime FROM Job,Pool"
540    " WHERE Job.Name='%s' AND Pool.Name='%s' AND Job.PoolId=Pool.PoolId"
541    " ORDER by Job.StartTime";
542
543 /* Get Client names in Pool */
544 const char *sql_client =
545    "SELECT DISTINCT Client.Name from Client,Pool,Job"
546    " WHERE Pool.Name='%s' AND Job.ClientId=Client.ClientId AND"
547    " Job.PoolId=Pool.PoolId";
548
549 /* Get JobIds from regex'ed Client names */
550 const char *sql_jobids_from_client =
551    "SELECT DISTINCT Job.JobId,Job.StartTime FROM Job,Pool,Client"
552    " WHERE Client.Name='%s' AND Pool.Name='%s' AND Job.PoolId=Pool.PoolId"
553    " AND Job.ClientId=Client.ClientId AND Job.Type IN ('B','C')"
554    " AND Job.JobStatus IN ('T','W')"
555    " ORDER by Job.StartTime";
556
557 /* Get Volume names in Pool */
558 const char *sql_vol = 
559    "SELECT DISTINCT VolumeName FROM Media,Pool WHERE"
560    " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
561    " Media.PoolId=Pool.PoolId AND Pool.Name='%s'";
562
563 /* Get JobIds from regex'ed Volume names */
564 const char *sql_jobids_from_vol =
565    "SELECT DISTINCT Job.JobId,Job.StartTime FROM Media,JobMedia,Job"
566    " WHERE Media.VolumeName='%s' AND Media.MediaId=JobMedia.MediaId"
567    " AND JobMedia.JobId=Job.JobId AND Job.Type IN ('B','C')"
568    " AND Job.JobStatus IN ('T','W') AND Media.Enabled=1"
569    " ORDER by Job.StartTime";
570
571 const char *sql_smallest_vol = 
572    "SELECT Media.MediaId FROM Media,Pool,JobMedia WHERE"
573    " Media.MediaId in (SELECT DISTINCT MediaId from JobMedia) AND"
574    " Media.VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
575    " Media.PoolId=Pool.PoolId AND Pool.Name='%s'"
576    " ORDER BY VolBytes ASC LIMIT 1";
577
578 const char *sql_oldest_vol = 
579    "SELECT Media.MediaId FROM Media,Pool,JobMedia WHERE"
580    " Media.MediaId in (SELECT DISTINCT MediaId from JobMedia) AND"
581    " Media.VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
582    " Media.PoolId=Pool.PoolId AND Pool.Name='%s'"
583    " ORDER BY LastWritten ASC LIMIT 1";
584
585 /* Get JobIds when we have selected MediaId */
586 const char *sql_jobids_from_mediaid =
587    "SELECT DISTINCT Job.JobId,Job.StartTime FROM JobMedia,Job"
588    " WHERE JobMedia.JobId=Job.JobId AND JobMedia.MediaId IN (%s)"
589    " AND Job.Type IN ('B','C') AND Job.JobStatus IN ('T','W')"
590    " ORDER by Job.StartTime";
591
592 /* Get the number of bytes in the pool */
593 const char *sql_pool_bytes =
594    "SELECT SUM(JobBytes) FROM Job WHERE JobId IN"
595    " (SELECT DISTINCT Job.JobId from Pool,Job,Media,JobMedia WHERE"
596    " Pool.Name='%s' AND Media.PoolId=Pool.PoolId AND"
597    " VolStatus in ('Full','Used','Error','Append') AND Media.Enabled=1 AND"
598    " Job.Type IN ('B','C') AND Job.JobStatus IN ('T','W') AND"
599    " JobMedia.JobId=Job.JobId AND Job.PoolId=Media.PoolId)";
600
601 /* Get the number of bytes in the Jobs */
602 const char *sql_job_bytes =
603    "SELECT SUM(JobBytes) FROM Job WHERE JobId IN (%s)";
604
605 /* Get Media Ids in Pool */
606 const char *sql_mediaids =
607    "SELECT MediaId FROM Media,Pool WHERE"
608    " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
609    " Media.PoolId=Pool.PoolId AND Pool.Name='%s' ORDER BY LastWritten ASC";
610
611 /* Get JobIds in Pool longer than specified time */
612 const char *sql_pool_time = 
613    "SELECT DISTINCT Job.JobId FROM Pool,Job,Media,JobMedia WHERE"
614    " Pool.Name='%s' AND Media.PoolId=Pool.PoolId AND"
615    " VolStatus IN ('Full','Used','Error') AND Media.Enabled=1 AND"
616    " Job.Type IN ('B','C') AND Job.JobStatus IN ('T','W') AND"
617    " JobMedia.JobId=Job.JobId AND Job.PoolId=Media.PoolId"
618    " AND Job.RealEndTime<='%s'";
619
620 /* Get JobIds from successfully completed backup jobs which have not been copied before */
621 const char *sql_jobids_of_pool_uncopied_jobs =
622    "SELECT DISTINCT Job.JobId,Job.StartTime FROM Job,Pool"
623    " WHERE Pool.Name = '%s' AND Pool.PoolId = Job.PoolId"
624    " AND Job.Type = 'B' AND Job.JobStatus IN ('T','W')"
625    " AND Job.jobBytes > 0"
626    " AND Job.JobId NOT IN"
627    " (SELECT PriorJobId FROM Job WHERE"
628    " Type IN ('B','C') AND Job.JobStatus IN ('T','W')"
629    " AND PriorJobId != 0)"
630    " ORDER by Job.StartTime";
631
632 /*
633 * const char *sql_ujobid =
634 *   "SELECT DISTINCT Job.Job from Client,Pool,Media,Job,JobMedia "
635 *   " WHERE Media.PoolId=Pool.PoolId AND Pool.Name='%s' AND"
636 *   " JobMedia.JobId=Job.JobId AND Job.PoolId=Media.PoolId";
637 */
638
639 /*
640  *
641  * This is the central piece of code that finds a job or jobs 
642  *   actually JobIds to migrate.  It first looks to see if one
643  *   has been "manually" specified in jcr->MigrateJobId, and if
644  *   so, it returns that JobId to be run.  Otherwise, it
645  *   examines the Selection Type to see what kind of migration
646  *   we are doing (Volume, Job, Client, ...) and applies any
647  *   Selection Pattern if appropriate to obtain a list of JobIds.
648  *   Finally, it will loop over all the JobIds found, except the last
649  *   one starting a new job with MigrationJobId set to that JobId, and
650  *   finally, it returns the last JobId to the caller.
651  *
652  * Returns: -1  on error
653  *           0  if no jobs to migrate
654  *           1  if OK and jcr->previous_jr filled in
655  */
656 static int getJob_to_migrate(JCR *jcr)
657 {
658    char ed1[30], ed2[30];
659    POOL_MEM query(PM_MESSAGE);
660    JobId_t JobId;
661    DBId_t DBId = 0;
662    int stat;
663    char *p;
664    idpkt ids, mid, jids;
665    db_int64_ctx ctx;
666    int64_t pool_bytes;
667    time_t ttime;
668    struct tm tm;
669    char dt[MAX_TIME_LENGTH];
670    int count = 0;
671
672    ids.list = get_pool_memory(PM_MESSAGE);
673    ids.list[0] = 0;
674    ids.count = 0;
675    mid.list = get_pool_memory(PM_MESSAGE);
676    mid.list[0] = 0;
677    mid.count = 0;
678    jids.list = get_pool_memory(PM_MESSAGE);
679    jids.list[0] = 0;
680    jids.count = 0;
681
682    /*
683     * If MigrateJobId is set, then we migrate only that Job,
684     *  otherwise, we go through the full selection of jobs to
685     *  migrate.
686     */
687    if (jcr->MigrateJobId != 0) {
688       Dmsg1(dbglevel, "At Job start previous jobid=%u\n", jcr->MigrateJobId);
689       JobId = jcr->MigrateJobId;
690    } else {
691       switch (jcr->job->selection_type) {
692       case MT_JOB:
693          if (!regex_find_jobids(jcr, &ids, sql_job, sql_jobids_from_job, "Job")) {
694             goto bail_out;
695          } 
696          break;
697       case MT_CLIENT:
698          if (!regex_find_jobids(jcr, &ids, sql_client, sql_jobids_from_client, "Client")) {
699             goto bail_out;
700          } 
701          break;
702       case MT_VOLUME:
703          if (!regex_find_jobids(jcr, &ids, sql_vol, sql_jobids_from_vol, "Volume")) {
704             goto bail_out;
705          } 
706          break;
707       case MT_SQLQUERY:
708          if (!jcr->job->selection_pattern) {
709             Jmsg(jcr, M_FATAL, 0, _("No %s SQL selection pattern specified.\n"), jcr->get_OperationName());
710             goto bail_out;
711          }
712          Dmsg1(dbglevel, "SQL=%s\n", jcr->job->selection_pattern);
713          if (!db_sql_query(jcr->db, jcr->job->selection_pattern,
714               unique_dbid_handler, (void *)&ids)) {
715             Jmsg(jcr, M_FATAL, 0,
716                  _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
717             goto bail_out;
718          }
719          break;
720       case MT_SMALLEST_VOL:
721          if (!find_mediaid_then_jobids(jcr, &ids, sql_smallest_vol, "Smallest Volume")) {
722             goto bail_out;
723          }
724          break;
725       case MT_OLDEST_VOL:
726          if (!find_mediaid_then_jobids(jcr, &ids, sql_oldest_vol, "Oldest Volume")) {
727             goto bail_out;
728          }
729          break;
730       case MT_POOL_OCCUPANCY:
731          ctx.count = 0;
732          /* Find count of bytes in pool */
733          Mmsg(query, sql_pool_bytes, jcr->rpool->name());
734          if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) {
735             Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
736             goto bail_out;
737          }
738          if (ctx.count == 0) {
739             Jmsg(jcr, M_INFO, 0, _("No Volumes found to %s.\n"), jcr->get_ActionName(0));
740             goto ok_out;
741          }
742          pool_bytes = ctx.value;
743          Dmsg2(dbglevel, "highbytes=%lld pool=%lld\n", jcr->rpool->MigrationHighBytes,
744                pool_bytes);
745          if (pool_bytes < (int64_t)jcr->rpool->MigrationHighBytes) {
746             Jmsg(jcr, M_INFO, 0, _("No Volumes found to %s.\n"), jcr->get_ActionName(0));
747             goto ok_out;
748          }
749          Dmsg0(dbglevel, "We should do Occupation migration.\n");
750
751          ids.count = 0;
752          /* Find a list of MediaIds that could be migrated */
753          Mmsg(query, sql_mediaids, jcr->rpool->name());
754          Dmsg1(dbglevel, "query=%s\n", query.c_str());
755          if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)&ids)) {
756             Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
757             goto bail_out;
758          }
759          if (ids.count == 0) {
760             Jmsg(jcr, M_INFO, 0, _("No Volumes found to %s.\n"), jcr->get_ActionName(0));
761             goto ok_out;
762          }
763          Dmsg2(dbglevel, "Pool Occupancy ids=%d MediaIds=%s\n", ids.count, ids.list);
764
765          if (!find_jobids_from_mediaid_list(jcr, &ids, "Volume")) {
766             goto bail_out;
767          }
768          /* ids == list of jobs  */
769          p = ids.list;
770          for (int i=0; i < (int)ids.count; i++) {
771             stat = get_next_dbid_from_list(&p, &DBId);
772             Dmsg2(dbglevel, "get_next_dbid stat=%d JobId=%u\n", stat, (uint32_t)DBId);
773             if (stat < 0) {
774                Jmsg(jcr, M_FATAL, 0, _("Invalid JobId found.\n"));
775                goto bail_out;
776             } else if (stat == 0) {
777                break;
778             }
779
780             mid.count = 1;
781             Mmsg(mid.list, "%s", edit_int64(DBId, ed1));
782             if (jids.count > 0) {
783                pm_strcat(jids.list, ",");
784             }
785             pm_strcat(jids.list, mid.list);
786             jids.count += mid.count;
787
788             /* Find count of bytes from Jobs */
789             Mmsg(query, sql_job_bytes, mid.list);
790             Dmsg1(dbglevel, "Jobbytes query: %s\n", query.c_str());
791             if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) {
792                Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
793                goto bail_out;
794             }
795             pool_bytes -= ctx.value;
796             Dmsg2(dbglevel, "Total %s Job bytes=%s\n", jcr->get_ActionName(0), edit_int64_with_commas(ctx.value, ed1));
797             Dmsg2(dbglevel, "lowbytes=%s poolafter=%s\n", 
798                   edit_int64_with_commas(jcr->rpool->MigrationLowBytes, ed1),
799                   edit_int64_with_commas(pool_bytes, ed2));
800             if (pool_bytes <= (int64_t)jcr->rpool->MigrationLowBytes) {
801                Dmsg0(dbglevel, "We should be done.\n");
802                break;
803             }
804          }
805          /* Transfer jids to ids, where the jobs list is expected */
806          ids.count = jids.count;
807          pm_strcpy(ids.list, jids.list);
808          Dmsg2(dbglevel, "Pool Occupancy ids=%d JobIds=%s\n", ids.count, ids.list);
809          break;
810       case MT_POOL_TIME:
811          ttime = time(NULL) - (time_t)jcr->rpool->MigrationTime;
812          (void)localtime_r(&ttime, &tm);
813          strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
814
815          ids.count = 0;
816          Mmsg(query, sql_pool_time, jcr->rpool->name(), dt);
817          Dmsg1(dbglevel, "query=%s\n", query.c_str());
818          if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)&ids)) {
819             Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
820             goto bail_out;
821          }
822          if (ids.count == 0) {
823             Jmsg(jcr, M_INFO, 0, _("No Volumes found to %s.\n"), jcr->get_ActionName(0));
824             goto ok_out;
825          }
826          Dmsg2(dbglevel, "PoolTime ids=%d JobIds=%s\n", ids.count, ids.list);
827          break;
828       case MT_POOL_UNCOPIED_JOBS:
829          if (!find_jobids_of_pool_uncopied_jobs(jcr, &ids)) {
830             goto bail_out;
831          } 
832          break;
833       default:
834          Jmsg(jcr, M_FATAL, 0, _("Unknown %s Selection Type.\n"), jcr->get_OperationName());
835          goto bail_out;
836       }
837
838       /*
839        * Loop over all jobids except the last one, sending
840        * them to start_migration_job(), which will start a job
841        * for each of them.  For the last JobId, we handle it below.
842        */
843       p = ids.list;
844       if (ids.count == 0) {
845          Jmsg(jcr, M_INFO, 0, _("No JobIds found to %s.\n"), jcr->get_ActionName(0));
846          goto ok_out;
847       }
848
849       Jmsg(jcr, M_INFO, 0, _("The following %u JobId%s chosen to be %s: %s\n"),
850          ids.count, (ids.count < 2) ? _(" was") : _("s were"),
851          jcr->get_ActionName(1), ids.list);
852
853       Dmsg2(dbglevel, "Before loop count=%d ids=%s\n", ids.count, ids.list);
854       for (int i=1; i < (int)ids.count; i++) {
855          JobId = 0;
856          stat = get_next_jobid_from_list(&p, &JobId);
857          Dmsg3(dbglevel, "getJobid_no=%d stat=%d JobId=%u\n", i, stat, JobId);
858          if (stat < 0) {
859             Jmsg(jcr, M_FATAL, 0, _("Invalid JobId found.\n"));
860             goto bail_out;
861          } else if (stat == 0) {
862             Jmsg(jcr, M_INFO, 0, _("No JobIds found to %s.\n"), jcr->get_ActionName(0));
863             goto ok_out;
864          }
865          jcr->MigrateJobId = JobId;
866          start_migration_job(jcr);
867          Dmsg0(dbglevel, "Back from start_migration_job\n");
868       }
869    
870       /* Now get the last JobId and handle it in the current job */
871       JobId = 0;
872       stat = get_next_jobid_from_list(&p, &JobId);
873       Dmsg2(dbglevel, "Last get_next_jobid stat=%d JobId=%u\n", stat, (int)JobId);
874       if (stat < 0) {
875          Jmsg(jcr, M_FATAL, 0, _("Invalid JobId found.\n"));
876          goto bail_out;
877       } else if (stat == 0) {
878          Jmsg(jcr, M_INFO, 0, _("No JobIds found to %s.\n"), jcr->get_ActionName(0));
879          goto ok_out;
880       }
881    }
882
883    jcr->previous_jr.JobId = JobId;
884    Dmsg1(dbglevel, "Previous jobid=%d\n", (int)jcr->previous_jr.JobId);
885
886    if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
887       Jmsg(jcr, M_FATAL, 0, _("Could not get job record for JobId %s to %s. ERR=%s"),
888            edit_int64(jcr->previous_jr.JobId, ed1),
889            jcr->get_ActionName(0),
890            db_strerror(jcr->db));
891       goto bail_out;
892    }
893
894    Jmsg(jcr, M_INFO, 0, _("%s using JobId=%s Job=%s\n"),
895       jcr->get_OperationName(),
896       edit_int64(jcr->previous_jr.JobId, ed1), jcr->previous_jr.Job);
897    Dmsg4(dbglevel, "%s JobId=%d  using JobId=%s Job=%s\n",
898       jcr->get_OperationName(),
899       jcr->JobId,
900       edit_int64(jcr->previous_jr.JobId, ed1), jcr->previous_jr.Job);
901    count = 1;
902
903 ok_out:
904    goto out;
905
906 bail_out:
907    count = -1;
908            
909 out:
910    free_pool_memory(ids.list);
911    free_pool_memory(mid.list);
912    free_pool_memory(jids.list);
913    return count;
914 }
915
916 static void start_migration_job(JCR *jcr)
917 {
918    UAContext *ua = new_ua_context(jcr);
919    char ed1[50];
920    ua->batch = true;
921    Mmsg(ua->cmd, "run job=\"%s\" jobid=%s ignoreduplicatecheck=yes pool=\"%s\"", 
922         jcr->job->name(), edit_uint64(jcr->MigrateJobId, ed1),
923         jcr->pool->name());
924    Dmsg2(dbglevel, "=============== %s cmd=%s\n", jcr->get_OperationName(), ua->cmd);
925    parse_ua_args(ua);                 /* parse command */
926    JobId_t jobid = run_cmd(ua, ua->cmd);
927    if (jobid == 0) {
928       Jmsg(jcr, M_ERROR, 0, _("Could not start migration job.\n"));
929    } else {
930       Jmsg(jcr, M_INFO, 0, _("%s JobId %d started.\n"), jcr->get_OperationName(), (int)jobid);
931    }
932    free_ua_context(ua);
933 }
934
935 static bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1,
936                  const char *type) 
937 {
938    bool ok = false;
939    POOL_MEM query(PM_MESSAGE);
940
941    ids->count = 0;
942    /* Basic query for MediaId */
943    Mmsg(query, query1, jcr->rpool->name());
944    if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) {
945       Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
946       goto bail_out;
947    }
948    if (ids->count == 0) {
949       Jmsg(jcr, M_INFO, 0, _("No %s found to %s.\n"), type, jcr->get_ActionName(0));
950       ok = true;         /* Not an error */
951       goto bail_out;
952    } else if (ids->count != 1) {
953       Jmsg(jcr, M_FATAL, 0, _("SQL error. Expected 1 MediaId got %d\n"), ids->count);
954       goto bail_out;
955    }
956    Dmsg2(dbglevel, "%s MediaIds=%s\n", type, ids->list);
957
958    ok = find_jobids_from_mediaid_list(jcr, ids, type);
959
960 bail_out:
961    return ok;
962 }
963
964 /* 
965  * This routine returns:
966  *    false       if an error occurred
967  *    true        otherwise
968  *    ids.count   number of jobids found (may be zero)
969  */       
970 static bool find_jobids_from_mediaid_list(JCR *jcr, idpkt *ids, const char *type) 
971 {
972    bool ok = false;
973    POOL_MEM query(PM_MESSAGE);
974
975    Mmsg(query, sql_jobids_from_mediaid, ids->list);
976    ids->count = 0;
977    if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) {
978       Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
979       goto bail_out;
980    }
981    if (ids->count == 0) {
982       Jmsg(jcr, M_INFO, 0, _("No %ss found to %s.\n"), type, jcr->get_ActionName(0));
983    }
984    ok = true;
985
986 bail_out:
987    return ok;
988 }
989
990 /* 
991  * This routine returns:
992  *    false       if an error occurred
993  *    true        otherwise
994  *    ids.count   number of jobids found (may be zero)
995  */       
996 static bool find_jobids_of_pool_uncopied_jobs(JCR *jcr, idpkt *ids) 
997 {
998    bool ok = false;
999    POOL_MEM query(PM_MESSAGE);
1000
1001    /* Only a copy job is allowed */
1002    if (jcr->getJobType() != JT_COPY) {
1003       Jmsg(jcr, M_FATAL, 0,
1004            _("Selection Type 'pooluncopiedjobs' only applies to Copy Jobs"));
1005       goto bail_out;
1006    }
1007
1008    Dmsg1(dbglevel, "copy selection pattern=%s\n", jcr->rpool->name());
1009    Mmsg(query, sql_jobids_of_pool_uncopied_jobs, jcr->rpool->name());
1010    Dmsg1(dbglevel, "get uncopied jobs query=%s\n", query.c_str());
1011    if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) {
1012       Jmsg(jcr, M_FATAL, 0,
1013            _("SQL to get uncopied jobs failed. ERR=%s\n"), db_strerror(jcr->db));
1014       goto bail_out;
1015    }
1016    ok = true;
1017
1018 bail_out:
1019    return ok;
1020 }
1021
1022 static bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1,
1023                  const char *query2, const char *type) 
1024 {
1025    dlist *item_chain;
1026    uitem *item = NULL;
1027    uitem *last_item = NULL;
1028    regex_t preg;
1029    char prbuf[500];
1030    int rc;
1031    bool ok = false;
1032    POOL_MEM query(PM_MESSAGE);
1033
1034    item_chain = New(dlist(item, &item->link));
1035    if (!jcr->job->selection_pattern) {
1036       Jmsg(jcr, M_FATAL, 0, _("No %s %s selection pattern specified.\n"),
1037          jcr->get_OperationName(), type);
1038       goto bail_out;
1039    }
1040    Dmsg1(dbglevel, "regex-sel-pattern=%s\n", jcr->job->selection_pattern);
1041    /* Basic query for names */
1042    Mmsg(query, query1, jcr->rpool->name());
1043    Dmsg1(dbglevel, "get name query1=%s\n", query.c_str());
1044    if (!db_sql_query(jcr->db, query.c_str(), unique_name_handler, 
1045         (void *)item_chain)) {
1046       Jmsg(jcr, M_FATAL, 0,
1047            _("SQL to get %s failed. ERR=%s\n"), type, db_strerror(jcr->db));
1048       goto bail_out;
1049    }
1050    Dmsg1(dbglevel, "query1 returned %d names\n", item_chain->size());
1051    if (item_chain->size() == 0) {
1052       Jmsg(jcr, M_INFO, 0, _("Query of Pool \"%s\" returned no Jobs to %s.\n"),
1053            jcr->rpool->name(), jcr->get_ActionName(0));
1054       ok = true;
1055       goto bail_out;               /* skip regex match */
1056    } else {
1057       /* Compile regex expression */
1058       rc = regcomp(&preg, jcr->job->selection_pattern, REG_EXTENDED);
1059       if (rc != 0) {
1060          regerror(rc, &preg, prbuf, sizeof(prbuf));
1061          Jmsg(jcr, M_FATAL, 0, _("Could not compile regex pattern \"%s\" ERR=%s\n"),
1062               jcr->job->selection_pattern, prbuf);
1063          goto bail_out;
1064       }
1065       /* Now apply the regex to the names and remove any item not matched */
1066       foreach_dlist(item, item_chain) {
1067          const int nmatch = 30;
1068          regmatch_t pmatch[nmatch];
1069          if (last_item) {
1070             Dmsg1(dbglevel, "Remove item %s\n", last_item->item);
1071             free(last_item->item);
1072             item_chain->remove(last_item);
1073          }
1074          Dmsg1(dbglevel, "get name Item=%s\n", item->item);
1075          rc = regexec(&preg, item->item, nmatch, pmatch,  0);
1076          if (rc == 0) {
1077             last_item = NULL;   /* keep this one */
1078          } else {   
1079             last_item = item;
1080          }
1081       }
1082       if (last_item) {
1083          free(last_item->item);
1084          Dmsg1(dbglevel, "Remove item %s\n", last_item->item);
1085          item_chain->remove(last_item);
1086       }
1087       regfree(&preg);
1088    }
1089    if (item_chain->size() == 0) {
1090       Jmsg(jcr, M_INFO, 0, _("Regex pattern matched no Jobs to %s.\n"), jcr->get_ActionName(0));
1091       ok = true;
1092       goto bail_out;               /* skip regex match */
1093    }
1094
1095    /* 
1096     * At this point, we have a list of items in item_chain
1097     *  that have been matched by the regex, so now we need
1098     *  to look up their jobids.
1099     */
1100    ids->count = 0;
1101    foreach_dlist(item, item_chain) {
1102       Dmsg2(dbglevel, "Got %s: %s\n", type, item->item);
1103       Mmsg(query, query2, item->item, jcr->rpool->name());
1104       Dmsg1(dbglevel, "get id from name query2=%s\n", query.c_str());
1105       if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) {
1106          Jmsg(jcr, M_FATAL, 0,
1107               _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
1108          goto bail_out;
1109       }
1110    }
1111    if (ids->count == 0) {
1112       Jmsg(jcr, M_INFO, 0, _("No %ss found to %s.\n"), type, jcr->get_ActionName(0));
1113    }
1114    ok = true;
1115
1116 bail_out:
1117    Dmsg2(dbglevel, "Count=%d Jobids=%s\n", ids->count, ids->list);
1118    foreach_dlist(item, item_chain) {
1119       free(item->item);
1120    }
1121    delete item_chain;
1122    return ok;
1123 }
1124
1125 /*
1126  * Release resources allocated during backup.
1127  */
1128 void migration_cleanup(JCR *jcr, int TermCode)
1129 {
1130    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
1131    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], elapsed[50];
1132    char ec6[50], ec7[50], ec8[50];
1133    char term_code[100], sd_term_msg[100];
1134    const char *term_msg;
1135    int msg_type = M_INFO;
1136    MEDIA_DBR mr;
1137    double kbps;
1138    utime_t RunTime;
1139    JCR *mig_jcr = jcr->mig_jcr;
1140    POOL_MEM query(PM_MESSAGE);
1141
1142    Dmsg2(100, "Enter migrate_cleanup %d %c\n", TermCode, TermCode);
1143    update_job_end(jcr, TermCode);
1144    memset(&mr, 0, sizeof(mr));
1145
1146    /* 
1147     * Check if we actually did something.  
1148     *  mig_jcr is jcr of the newly migrated job.
1149     */
1150    if (mig_jcr) {
1151       char old_jobid[50], new_jobid[50];
1152
1153       edit_uint64(jcr->previous_jr.JobId, old_jobid);
1154       edit_uint64(mig_jcr->jr.JobId, new_jobid);
1155
1156       mig_jcr->JobFiles = jcr->JobFiles = jcr->SDJobFiles;
1157       mig_jcr->JobBytes = jcr->JobBytes = jcr->SDJobBytes;
1158       mig_jcr->VolSessionId = jcr->VolSessionId;
1159       mig_jcr->VolSessionTime = jcr->VolSessionTime;
1160       mig_jcr->jr.RealEndTime = 0; 
1161       mig_jcr->jr.PriorJobId = jcr->previous_jr.JobId;
1162
1163       update_job_end(mig_jcr, TermCode);
1164      
1165       /* Update final items to set them to the previous job's values */
1166       Mmsg(query, "UPDATE Job SET StartTime='%s',EndTime='%s',"
1167                   "JobTDate=%s WHERE JobId=%s", 
1168          jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime, 
1169          edit_uint64(jcr->previous_jr.JobTDate, ec1),
1170          new_jobid);
1171       db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
1172
1173       /*
1174        * If we terminated a migration normally:
1175        *   - mark the previous job as migrated
1176        *   - move any Log records to the new JobId
1177        *   - Purge the File records from the previous job
1178        */
1179       if (jcr->getJobType() == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
1180          Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
1181               (char)JT_MIGRATED_JOB, old_jobid);
1182          db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
1183          UAContext *ua = new_ua_context(jcr);
1184          /* Move JobLog to new JobId */
1185          Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
1186            new_jobid, old_jobid);
1187          db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
1188
1189          if (jcr->job->PurgeMigrateJob) {
1190             /* Purge old Job record */
1191             purge_jobs_from_catalog(ua, old_jobid);
1192          } else {
1193             /* Purge all old file records, but leave Job record */
1194             purge_files_from_jobs(ua, old_jobid);
1195          }
1196
1197          free_ua_context(ua);
1198       } 
1199
1200       /*
1201        * If we terminated a Copy (rather than a Migration) normally:
1202        *   - copy any Log records to the new JobId
1203        *   - set type="Job Copy" for the new job
1204        */
1205       if (jcr->getJobType() == JT_COPY && jcr->JobStatus == JS_Terminated) {
1206          /* Copy JobLog to new JobId */
1207          Mmsg(query, "INSERT INTO Log (JobId, Time, LogText ) " 
1208                       "SELECT %s, Time, LogText FROM Log WHERE JobId=%s",
1209               new_jobid, old_jobid);
1210          db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
1211          Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
1212               (char)JT_JOB_COPY, new_jobid);
1213          db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
1214       } 
1215
1216       if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
1217          Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
1218             db_strerror(jcr->db));
1219          jcr->setJobStatus(JS_ErrorTerminated);
1220       }
1221
1222       update_bootstrap_file(mig_jcr);
1223
1224       if (!db_get_job_volume_names(mig_jcr, mig_jcr->db, mig_jcr->jr.JobId, &mig_jcr->VolumeName)) {
1225          /*
1226           * Note, if the job has failed, most likely it did not write any
1227           *  tape, so suppress this "error" message since in that case
1228           *  it is normal.  Or look at it the other way, only for a
1229           *  normal exit should we complain about this error.
1230           */
1231          if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
1232             Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(mig_jcr->db));
1233          }
1234          mig_jcr->VolumeName[0] = 0;         /* none */
1235       }
1236
1237       if (mig_jcr->VolumeName[0]) {
1238          /* Find last volume name. Multiple vols are separated by | */
1239          char *p = strrchr(mig_jcr->VolumeName, '|');
1240          if (p) {
1241             p++;                         /* skip | */
1242          } else {
1243             p = mig_jcr->VolumeName;     /* no |, take full name */
1244          }
1245          bstrncpy(mr.VolumeName, p, sizeof(mr.VolumeName));
1246          if (!db_get_media_record(jcr, jcr->db, &mr)) {
1247             Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
1248                mr.VolumeName, db_strerror(jcr->db));
1249          }
1250       }
1251
1252       switch (jcr->JobStatus) {
1253       case JS_Terminated:
1254          if (jcr->JobErrors || jcr->SDErrors) {
1255             term_msg = _("%s OK -- with warnings");
1256          } else {
1257             term_msg = _("%s OK");
1258          }
1259          break;
1260       case JS_FatalError:
1261       case JS_ErrorTerminated:
1262          term_msg = _("*** %s Error ***");
1263          msg_type = M_ERROR;          /* Generate error message */
1264          if (jcr->store_bsock) {
1265             bnet_sig(jcr->store_bsock, BNET_TERMINATE);
1266             if (jcr->SD_msg_chan) {
1267                pthread_cancel(jcr->SD_msg_chan);
1268             }
1269          }
1270          break;
1271       case JS_Canceled:
1272          term_msg = _("%s Canceled");
1273          if (jcr->store_bsock) {
1274             bnet_sig(jcr->store_bsock, BNET_TERMINATE);
1275             if (jcr->SD_msg_chan) {
1276                pthread_cancel(jcr->SD_msg_chan);
1277             }
1278          }
1279          break;
1280       default:
1281          term_msg = _("Inappropriate %s term code");
1282          break;
1283       }
1284    } else {
1285       if (jcr->getJobType() == JT_MIGRATE && jcr->previous_jr.JobId != 0) {
1286          /* Mark previous job as migrated */
1287          Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
1288               (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
1289          db_sql_query(jcr->db, query.c_str(), NULL, NULL);
1290       }
1291       term_msg = _("%s -- no files to %s");
1292    }
1293
1294    bsnprintf(term_code, sizeof(term_code), term_msg, jcr->get_OperationName(), jcr->get_ActionName(0));
1295    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
1296    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
1297    RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
1298    if (RunTime <= 0) {
1299       kbps = 0;
1300    } else {
1301       kbps = (double)jcr->SDJobBytes / (1000 * RunTime);
1302    }
1303
1304    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
1305
1306    Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
1307 "  Build OS:               %s %s %s\n"
1308 "  Prev Backup JobId:      %s\n"
1309 "  Prev Backup Job:        %s\n"
1310 "  New Backup JobId:       %s\n"
1311 "  Current JobId:          %s\n"
1312 "  Current Job:            %s\n"
1313 "  Backup Level:           %s%s\n"
1314 "  Client:                 %s\n"
1315 "  FileSet:                \"%s\" %s\n"
1316 "  Read Pool:              \"%s\" (From %s)\n"
1317 "  Read Storage:           \"%s\" (From %s)\n"
1318 "  Write Pool:             \"%s\" (From %s)\n"
1319 "  Write Storage:          \"%s\" (From %s)\n"
1320 "  Catalog:                \"%s\" (From %s)\n"
1321 "  Start time:             %s\n"
1322 "  End time:               %s\n"
1323 "  Elapsed time:           %s\n"
1324 "  Priority:               %d\n"
1325 "  SD Files Written:       %s\n"
1326 "  SD Bytes Written:       %s (%sB)\n"
1327 "  Rate:                   %.1f KB/s\n"
1328 "  Volume name(s):         %s\n"
1329 "  Volume Session Id:      %d\n"
1330 "  Volume Session Time:    %d\n"
1331 "  Last Volume Bytes:      %s (%sB)\n"
1332 "  SD Errors:              %d\n"
1333 "  SD termination status:  %s\n"
1334 "  Termination:            %s\n\n"),
1335         BACULA, my_name, VERSION, LSMDATE,
1336         HOST_OS, DISTNAME, DISTVER,
1337         edit_uint64(jcr->previous_jr.JobId, ec6),
1338         jcr->previous_jr.Job,
1339         mig_jcr ? edit_uint64(mig_jcr->jr.JobId, ec7) : "0",
1340         edit_uint64(jcr->jr.JobId, ec8),
1341         jcr->jr.Job,
1342         level_to_str(jcr->getJobLevel()), jcr->since,
1343         jcr->client->name(),
1344         jcr->fileset->name(), jcr->FSCreateTime,
1345         jcr->rpool->name(), jcr->rpool_source,
1346         jcr->rstore?jcr->rstore->name():"*None*", 
1347         NPRT(jcr->rstore_source), 
1348         jcr->pool->name(), jcr->pool_source,
1349         jcr->wstore?jcr->wstore->name():"*None*", 
1350         NPRT(jcr->wstore_source),
1351         jcr->catalog->name(), jcr->catalog_source,
1352         sdt,
1353         edt,
1354         edit_utime(RunTime, elapsed, sizeof(elapsed)),
1355         jcr->JobPriority,
1356         edit_uint64_with_commas(jcr->SDJobFiles, ec1),
1357         edit_uint64_with_commas(jcr->SDJobBytes, ec2),
1358         edit_uint64_with_suffix(jcr->SDJobBytes, ec3),
1359         (float)kbps,
1360         mig_jcr ? mig_jcr->VolumeName : "",
1361         jcr->VolSessionId,
1362         jcr->VolSessionTime,
1363         edit_uint64_with_commas(mr.VolBytes, ec4),
1364         edit_uint64_with_suffix(mr.VolBytes, ec5),
1365         jcr->SDErrors,
1366         sd_term_msg,
1367         term_code);
1368
1369    Dmsg1(100, "migrate_cleanup() mig_jcr=0x%x\n", jcr->mig_jcr);
1370    if (jcr->mig_jcr) {
1371       free_jcr(jcr->mig_jcr);
1372       jcr->mig_jcr = NULL;
1373    }
1374    Dmsg0(100, "Leave migrate_cleanup()\n");
1375 }
1376
1377 /* 
1378  * Return next DBId from comma separated list   
1379  *
1380  * Returns:
1381  *   1 if next DBId returned
1382  *   0 if no more DBIds are in list
1383  *  -1 there is an error
1384  */
1385 static int get_next_dbid_from_list(char **p, DBId_t *DBId)
1386 {
1387    const int maxlen = 30;
1388    char id[maxlen+1];
1389    char *q = *p;
1390
1391    id[0] = 0;
1392    for (int i=0; i<maxlen; i++) {
1393       if (*q == 0) {
1394          break;
1395       } else if (*q == ',') {
1396          q++;
1397          break;
1398       }
1399       id[i] = *q++;
1400       id[i+1] = 0;
1401    }
1402    if (id[0] == 0) {
1403       return 0;
1404    } else if (!is_a_number(id)) {
1405       return -1;                      /* error */
1406    }
1407    *p = q;
1408    *DBId = str_to_int64(id);
1409    return 1;
1410 }
1411
1412 bool set_migration_wstorage(JCR *jcr, POOL *pool)
1413 {
1414    POOL *wpool = pool->NextPool;
1415
1416    if (!wpool) {
1417       Jmsg(jcr, M_FATAL, 0, _("No Next Pool specification found in Pool \"%s\".\n"),
1418          pool->hdr.name);
1419       return false;
1420    }
1421
1422    if (!wpool->storage || wpool->storage->size() == 0) {
1423       Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Next Pool \"%s\".\n"),
1424          wpool->name());
1425       return false;
1426    }
1427
1428    /* If pool storage specified, use it instead of job storage for backup */
1429    copy_wstorage(jcr, wpool->storage, _("Storage from Pool's NextPool resource"));
1430    return true;
1431 }