]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/job.c
Changes to get read storage correct for Virtual Backup.
[bacula/bacula] / bacula / src / dird / job.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 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 two of the GNU 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 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 Job processing routines
31  *
32  *     Kern Sibbald, October MM
33  *
34  *    Version $Id$
35  */
36
37 #include "bacula.h"
38 #include "dird.h"
39
40 /* Forward referenced subroutines */
41 static void *job_thread(void *arg);
42 static void job_monitor_watchdog(watchdog_t *self);
43 static void job_monitor_destructor(watchdog_t *self);
44 static bool job_check_maxwaittime(JCR *jcr);
45 static bool job_check_maxruntime(JCR *jcr);
46 static bool job_check_maxschedruntime(JCR *jcr);
47
48 /* Imported subroutines */
49 extern void term_scheduler();
50 extern void term_ua_server();
51
52 /* Imported variables */
53
54 jobq_t job_queue;
55
56 void init_job_server(int max_workers)
57 {
58    int stat;
59    watchdog_t *wd;
60
61    if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
62       berrno be;
63       Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.bstrerror(stat));
64    }
65    wd = new_watchdog();
66    wd->callback = job_monitor_watchdog;
67    wd->destructor = job_monitor_destructor;
68    wd->one_shot = false;
69    wd->interval = 60;
70    wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
71    register_watchdog(wd);
72 }
73
74 void term_job_server()
75 {
76    jobq_destroy(&job_queue);          /* ignore any errors */
77 }
78
79 /*
80  * Run a job -- typically called by the scheduler, but may also
81  *              be called by the UA (Console program).
82  *
83  *  Returns: 0 on failure
84  *           JobId on success
85  *
86  */
87 JobId_t run_job(JCR *jcr)
88 {
89    int stat;
90    if (setup_job(jcr)) {
91       Dmsg0(200, "Add jrc to work queue\n");
92       /* Queue the job to be run */
93       if ((stat = jobq_add(&job_queue, jcr)) != 0) {
94          berrno be;
95          Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
96          return 0;
97       }
98       return jcr->JobId;
99    }
100    return 0;
101 }            
102
103 bool setup_job(JCR *jcr) 
104 {
105    int errstat;
106
107    jcr->lock();
108    sm_check(__FILE__, __LINE__, true);
109    init_msg(jcr, jcr->messages);
110
111    /* Initialize termination condition variable */
112    if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
113       berrno be;
114       Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
115       jcr->unlock();
116       goto bail_out;
117    }
118    jcr->term_wait_inited = true;
119
120    create_unique_job_name(jcr, jcr->job->name());
121    set_jcr_job_status(jcr, JS_Created);
122    jcr->unlock();
123
124    /*
125     * Open database
126     */
127    Dmsg0(100, "Open database\n");
128    jcr->db=db_init(jcr, jcr->catalog->db_driver, jcr->catalog->db_name, 
129                    jcr->catalog->db_user,
130                    jcr->catalog->db_password, jcr->catalog->db_address,
131                    jcr->catalog->db_port, jcr->catalog->db_socket,
132                    jcr->catalog->mult_db_connections);
133    if (!jcr->db || !db_open_database(jcr, jcr->db)) {
134       Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
135                  jcr->catalog->db_name);
136       if (jcr->db) {
137          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
138          db_close_database(jcr, jcr->db);
139       }
140       goto bail_out;
141    }
142    Dmsg0(150, "DB opened\n");
143
144    if (!jcr->fname) {
145       jcr->fname = get_pool_memory(PM_FNAME);
146    }
147    if (!jcr->pool_source) {
148       jcr->pool_source = get_pool_memory(PM_MESSAGE);
149       pm_strcpy(jcr->pool_source, _("unknown source"));
150    }
151    Dmsg2(500, "pool=%s (From %s)\n", jcr->pool->name(), jcr->pool_source);
152    /* ****FIXME**** */
153    if (jcr->JobType == JT_MIGRATE || jcr->JobType == JT_COPY) {
154       if (!jcr->rpool_source) {
155          jcr->rpool_source = get_pool_memory(PM_MESSAGE);
156          pm_strcpy(jcr->rpool_source, _("unknown source"));
157       }
158    }
159
160    /*
161     * Create Job record
162     */
163    init_jcr_job_record(jcr);
164    if (!get_or_create_client_record(jcr)) {
165       goto bail_out;
166    }
167
168    if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
169       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
170       goto bail_out;
171    }
172    jcr->JobId = jcr->jr.JobId;
173    Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
174        jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
175
176    generate_daemon_event(jcr, "JobStart");
177
178    if (job_canceled(jcr)) {
179       goto bail_out;
180    }
181
182    /*
183     * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
184     *  this allows us to setup a proper job start record for restarting
185     *  in case of later errors.
186     */
187    switch (jcr->JobType) {
188    case JT_BACKUP:
189       if (!do_backup_init(jcr)) {
190          backup_cleanup(jcr, JS_ErrorTerminated);
191       }
192       break;
193    case JT_VERIFY:
194       if (!do_verify_init(jcr)) {
195          verify_cleanup(jcr, JS_ErrorTerminated);
196       }
197       break;
198    case JT_RESTORE:
199       if (!do_restore_init(jcr)) {
200          restore_cleanup(jcr, JS_ErrorTerminated);
201       }
202       break;
203    case JT_ADMIN:
204       if (!do_admin_init(jcr)) {
205          admin_cleanup(jcr, JS_ErrorTerminated);
206       }
207       break;
208    case JT_COPY:
209    case JT_MIGRATE:
210       if (!do_migration_init(jcr)) { 
211          migration_cleanup(jcr, JS_ErrorTerminated);
212       }
213       break;
214    default:
215       Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
216       set_jcr_job_status(jcr, JS_ErrorTerminated);
217       break;
218    }
219
220    generate_job_event(jcr, "JobInit");
221    Dsm_check(1);
222    return true;
223
224 bail_out:
225    return false;
226 }
227
228 void update_job_end(JCR *jcr, int TermCode)
229 {
230    dequeue_messages(jcr);             /* display any queued messages */
231    set_jcr_job_status(jcr, TermCode);
232    update_job_end_record(jcr);
233 }
234
235 /*
236  * This is the engine called by jobq.c:jobq_add() when we were pulled
237  *  from the work queue.
238  *  At this point, we are running in our own thread and all
239  *    necessary resources are allocated -- see jobq.c
240  */
241 static void *job_thread(void *arg)
242 {
243    JCR *jcr = (JCR *)arg;
244
245    pthread_detach(pthread_self());
246    Dsm_check(1);
247
248    Dmsg0(200, "=====Start Job=========\n");
249    set_jcr_job_status(jcr, JS_Running);   /* this will be set only if no error */
250    jcr->start_time = time(NULL);      /* set the real start time */
251    jcr->jr.StartTime = jcr->start_time;
252
253    if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
254        (utime_t)(jcr->start_time - jcr->sched_time)) {
255       set_jcr_job_status(jcr, JS_Canceled);
256       Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
257    }
258
259    if (job_check_maxschedruntime(jcr)) {
260       set_jcr_job_status(jcr, JS_Canceled);
261       Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
262    }
263
264    /* TODO : check if it is used somewhere */
265    if (jcr->job->RunScripts == NULL) {
266       Dmsg0(200, "Warning, job->RunScripts is empty\n");
267       jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
268    }
269
270    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
271       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
272    }
273
274    /* Run any script BeforeJob on dird */
275    run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
276
277    if (job_canceled(jcr)) {
278       update_job_end(jcr, jcr->JobStatus);
279
280    } else {
281       /*
282        * We re-update the job start record so that the start
283        *  time is set after the run before job.  This avoids
284        *  that any files created by the run before job will
285        *  be saved twice.  They will be backed up in the current
286        *  job, but not in the next one unless they are changed.
287        *  Without this, they will be backed up in this job and
288        *  in the next job run because in that case, their date
289        *   is after the start of this run.
290        */
291       jcr->start_time = time(NULL);
292       jcr->jr.StartTime = jcr->start_time;
293       if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
294          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
295       }
296       generate_job_event(jcr, "JobRun");
297
298       switch (jcr->JobType) {
299       case JT_BACKUP:
300          if (do_backup(jcr)) {
301             do_autoprune(jcr);
302          } else {
303             backup_cleanup(jcr, JS_ErrorTerminated);
304          }
305          break;
306       case JT_VERIFY:
307          if (do_verify(jcr)) {
308             do_autoprune(jcr);
309          } else {
310             verify_cleanup(jcr, JS_ErrorTerminated);
311          }
312          break;
313       case JT_RESTORE:
314          if (do_restore(jcr)) {
315             do_autoprune(jcr);
316          } else {
317             restore_cleanup(jcr, JS_ErrorTerminated);
318          }
319          break;
320       case JT_ADMIN:
321          if (do_admin(jcr)) {
322             do_autoprune(jcr);
323          } else {
324             admin_cleanup(jcr, JS_ErrorTerminated);
325          }
326          break;
327       case JT_COPY:
328       case JT_MIGRATE:
329          if (do_migration(jcr)) {
330             do_autoprune(jcr);
331          } else {
332             migration_cleanup(jcr, JS_ErrorTerminated);
333          }
334          break;
335       default:
336          Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
337          break;
338       }
339    }
340
341    run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
342
343    /* Send off any queued messages */
344    if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
345       dequeue_messages(jcr);
346    }
347
348    generate_daemon_event(jcr, "JobEnd");
349    Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
350    sm_check(__FILE__, __LINE__, true);
351    return NULL;
352 }
353
354
355 /*
356  * Cancel a job -- typically called by the UA (Console program), but may also
357  *              be called by the job watchdog.
358  *
359  *  Returns: true  if cancel appears to be successful
360  *           false on failure. Message sent to ua->jcr.
361  */
362 bool cancel_job(UAContext *ua, JCR *jcr)
363 {
364    BSOCK *sd, *fd;
365    char ed1[50];
366
367    set_jcr_job_status(jcr, JS_Canceled);
368
369    switch (jcr->JobStatus) {
370    case JS_Created:
371    case JS_WaitJobRes:
372    case JS_WaitClientRes:
373    case JS_WaitStoreRes:
374    case JS_WaitPriority:
375    case JS_WaitMaxJobs:
376    case JS_WaitStartTime:
377       ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
378               edit_uint64(jcr->JobId, ed1), jcr->Job);
379       jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
380       return true;
381
382    default:
383       /* Cancel File daemon */
384       if (jcr->file_bsock) {
385          ua->jcr->client = jcr->client;
386          if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
387             ua->error_msg(_("Failed to connect to File daemon.\n"));
388             return 0;
389          }
390          Dmsg0(200, "Connected to file daemon\n");
391          fd = ua->jcr->file_bsock;
392          bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
393          while (bnet_recv(fd) >= 0) {
394             ua->send_msg("%s", fd->msg);
395          }
396          bnet_sig(fd, BNET_TERMINATE);
397          bnet_close(fd);
398          ua->jcr->file_bsock = NULL;
399       }
400
401       /* Cancel Storage daemon */
402       if (jcr->store_bsock) {
403          if (!ua->jcr->wstorage) {
404             if (jcr->rstorage) {
405                copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); 
406             } else {
407                copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); 
408             }
409          } else {
410             USTORE store;
411             if (jcr->rstorage) {
412                store.store = jcr->rstore;
413             } else {
414                store.store = jcr->wstore;
415             }
416             set_wstorage(ua->jcr, &store);
417          }
418
419          if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
420             ua->error_msg(_("Failed to connect to Storage daemon.\n"));
421             return false;
422          }
423          Dmsg0(200, "Connected to storage daemon\n");
424          sd = ua->jcr->store_bsock;
425          sd->fsend("cancel Job=%s\n", jcr->Job);
426          while (sd->recv() >= 0) {
427             ua->send_msg("%s", sd->msg);
428          }
429          sd->signal(BNET_TERMINATE);
430          sd->close();
431          ua->jcr->store_bsock = NULL;
432       }
433    }
434
435    return true;
436 }
437
438 void cancel_storage_daemon_job(JCR *jcr)
439 {
440    UAContext *ua = new_ua_context(jcr);
441    JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
442    BSOCK *sd;
443
444    ua->jcr = control_jcr;
445    if (jcr->store_bsock) {
446       if (!ua->jcr->wstorage) {
447          if (jcr->rstorage) {
448             copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); 
449          } else {
450             copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); 
451          }
452       } else {
453          USTORE store;
454          if (jcr->rstorage) {
455             store.store = jcr->rstore;
456          } else {
457             store.store = jcr->wstore;
458          }
459          set_wstorage(ua->jcr, &store);
460       }
461
462       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
463          goto bail_out;
464       }
465       Dmsg0(200, "Connected to storage daemon\n");
466       sd = ua->jcr->store_bsock;
467       sd->fsend("cancel Job=%s\n", jcr->Job);
468       while (sd->recv() >= 0) {
469       }
470       sd->signal(BNET_TERMINATE);
471       sd->close();
472       ua->jcr->store_bsock = NULL;
473    }
474 bail_out:
475    free_jcr(control_jcr);
476    free_ua_context(ua);
477 }
478
479 static void job_monitor_destructor(watchdog_t *self)
480 {
481    JCR *control_jcr = (JCR *)self->data;
482
483    free_jcr(control_jcr);
484 }
485
486 static void job_monitor_watchdog(watchdog_t *self)
487 {
488    JCR *control_jcr, *jcr;
489
490    control_jcr = (JCR *)self->data;
491
492    Dsm_check(1);
493    Dmsg1(800, "job_monitor_watchdog %p called\n", self);
494
495    foreach_jcr(jcr) {
496       bool cancel = false;
497
498       if (jcr->JobId == 0 || job_canceled(jcr)) {
499          Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
500          continue;
501       }
502
503       /* check MaxWaitTime */
504       if (job_check_maxwaittime(jcr)) {
505          set_jcr_job_status(jcr, JS_Canceled);
506          Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
507          cancel = true;
508       /* check MaxRunTime */
509       } else if (job_check_maxruntime(jcr)) {
510          set_jcr_job_status(jcr, JS_Canceled);
511          Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
512          cancel = true;
513       /* check MaxRunSchedTime */ 
514       } else if (job_check_maxschedruntime(jcr)) {
515          set_jcr_job_status(jcr, JS_Canceled);
516          Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
517          cancel = true;
518       }
519
520       if (cancel) {
521          Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
522          UAContext *ua = new_ua_context(jcr);
523          ua->jcr = control_jcr;
524          cancel_job(ua, jcr);
525          free_ua_context(ua);
526          Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
527       }
528
529    }
530    /* Keep reference counts correct */
531    endeach_jcr(jcr);
532 }
533
534 /*
535  * Check if the maxwaittime has expired and it is possible
536  *  to cancel the job.
537  */
538 static bool job_check_maxwaittime(JCR *jcr)
539 {
540    bool cancel = false;
541    JOB *job = jcr->job;
542
543    if (!job_waiting(jcr)) {
544       return false;
545    }
546    Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
547    if (job->MaxWaitTime != 0 &&
548        (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
549       cancel = true;
550    }
551
552    return cancel;
553 }
554
555 /*
556  * Check if maxruntime has expired and if the job can be
557  *   canceled.
558  */
559 static bool job_check_maxruntime(JCR *jcr)
560 {
561    bool cancel = false;
562    JOB *job = jcr->job;
563
564    if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
565       return false;
566    }
567    if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
568        job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
569       return false;
570    }
571    Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
572          watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime, 
573          job->IncMaxRunTime, job->DiffMaxRunTime);
574
575    if (jcr->JobLevel == L_FULL && job->FullMaxRunTime != 0 &&
576          (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
577       cancel = true;
578    } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
579          (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
580       cancel = true;
581    } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
582          (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
583       cancel = true;
584    } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
585       cancel = true;
586    }
587  
588    return cancel;
589 }
590
591 /*
592  * Check if MaxRunSchedTime has expired and if the job can be
593  *   canceled.
594  */
595 static bool job_check_maxschedruntime(JCR *jcr)
596 {
597    if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
598       return false;
599    }
600    if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
601       Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
602             jcr, jcr->Job, jcr->job->MaxRunSchedTime);
603       return false;
604    }
605
606    return true;
607 }
608
609 /*
610  * Get or create a Pool record with the given name.
611  * Returns: 0 on error
612  *          poolid if OK
613  */
614 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
615 {
616    POOL_DBR pr;
617
618    memset(&pr, 0, sizeof(pr));
619    bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
620    Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
621
622    while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
623       /* Try to create the pool */
624       if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
625          Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
626             db_strerror(jcr->db));
627          return 0;
628       } else {
629          Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
630       }
631    }
632    return pr.PoolId;
633 }
634
635 /*
636  * Check for duplicate jobs.
637  *  Returns: true  if current job should continue
638  *           false if current job should terminate
639  */
640 bool allow_duplicate_job(JCR *jcr)
641 {
642    JOB *job = jcr->job;
643    JCR *djcr;                /* possible duplicate */
644
645    if (job->AllowDuplicateJobs) {
646       return true;
647    }
648    if (!job->AllowHigherDuplicates) {
649       foreach_jcr(djcr) {
650          char ec1[50];
651          if (strcmp(job->name(), djcr->job->name()) == 0) {
652             bool cancel_queued = false;
653             if (job->DuplicateJobProximity > 0) {
654                time_t now = time(NULL);
655                if ((now - djcr->start_time) > job->DuplicateJobProximity) {
656                   continue;               /* not really a duplicate */
657                }
658             }
659             /* Cancel */
660             if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
661                /* Zap current job */
662                Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
663                   edit_uint64(djcr->JobId, ec1));
664                return false;
665             }
666             /* If CancelQueuedDuplicates is set do so only if job is queued */
667             if (job->CancelQueuedDuplicates) {
668                 switch (djcr->JobStatus) {
669                 case JS_Created:
670                 case JS_WaitJobRes:
671                 case JS_WaitClientRes:
672                 case JS_WaitStoreRes:
673                 case JS_WaitPriority:
674                 case JS_WaitMaxJobs:
675                 case JS_WaitStartTime:
676                    cancel_queued = true;
677                    break;
678                 default:
679                    break;
680                 }
681             }
682             if (cancel_queued || job->CancelRunningDuplicates) {
683                UAContext *ua = new_ua_context(djcr);
684                Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"), 
685                   edit_uint64(djcr->JobId, ec1));
686                ua->jcr = djcr;
687                cancel_job(ua, djcr);
688                free_ua_context(ua);
689                Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
690             }
691          }
692       }
693    }
694    return true;   
695 }
696
697 void apply_pool_overrides(JCR *jcr)
698 {
699    bool pool_override = false;
700
701    if (jcr->run_pool_override) {
702       pm_strcpy(jcr->pool_source, _("Run pool override"));
703    }
704    /*
705     * Apply any level related Pool selections
706     */
707    switch (jcr->JobLevel) {
708    case L_FULL:
709       if (jcr->full_pool) {
710          jcr->pool = jcr->full_pool;
711          pool_override = true;
712          if (jcr->run_full_pool_override) {
713             pm_strcpy(jcr->pool_source, _("Run FullPool override"));
714          } else {
715             pm_strcpy(jcr->pool_source, _("Job FullPool override"));
716          }
717       }
718       break;
719    case L_INCREMENTAL:
720       if (jcr->inc_pool) {
721          jcr->pool = jcr->inc_pool;
722          pool_override = true;
723          if (jcr->run_inc_pool_override) {
724             pm_strcpy(jcr->pool_source, _("Run IncPool override"));
725          } else {
726             pm_strcpy(jcr->pool_source, _("Job IncPool override"));
727          }
728       }
729       break;
730    case L_DIFFERENTIAL:
731       if (jcr->diff_pool) {
732          jcr->pool = jcr->diff_pool;
733          pool_override = true;
734          if (jcr->run_diff_pool_override) {
735             pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
736          } else {
737             pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
738          }
739       }
740       break;
741    }
742    /* Update catalog if pool overridden */
743    if (pool_override && jcr->pool->catalog) {
744       jcr->catalog = jcr->pool->catalog;
745       pm_strcpy(jcr->catalog_source, _("Pool resource"));
746    }
747 }
748
749
750 /*
751  * Get or create a Client record for this Job
752  */
753 bool get_or_create_client_record(JCR *jcr)
754 {
755    CLIENT_DBR cr;
756
757    memset(&cr, 0, sizeof(cr));
758    bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
759    cr.AutoPrune = jcr->client->AutoPrune;
760    cr.FileRetention = jcr->client->FileRetention;
761    cr.JobRetention = jcr->client->JobRetention;
762    if (!jcr->client_name) {
763       jcr->client_name = get_pool_memory(PM_NAME);
764    }
765    pm_strcpy(jcr->client_name, jcr->client->hdr.name);
766    if (!db_create_client_record(jcr, jcr->db, &cr)) {
767       Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
768          db_strerror(jcr->db));
769       return false;
770    }
771    jcr->jr.ClientId = cr.ClientId;
772    if (cr.Uname[0]) {
773       if (!jcr->client_uname) {
774          jcr->client_uname = get_pool_memory(PM_NAME);
775       }
776       pm_strcpy(jcr->client_uname, cr.Uname);
777    }
778    Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
779       jcr->jr.ClientId);
780    return true;
781 }
782
783 bool get_or_create_fileset_record(JCR *jcr)
784 {
785    FILESET_DBR fsr;
786    /*
787     * Get or Create FileSet record
788     */
789    memset(&fsr, 0, sizeof(FILESET_DBR));
790    bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
791    if (jcr->fileset->have_MD5) {
792       struct MD5Context md5c;
793       unsigned char digest[MD5HashSize];
794       memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
795       MD5Final(digest, &md5c);
796       /*
797        * Keep the flag (last arg) set to false otherwise old FileSets will
798        * get new MD5 sums and the user will get Full backups on everything
799        */
800       bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
801       bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
802    } else {
803       Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
804    }
805    if (!jcr->fileset->ignore_fs_changes ||
806        !db_get_fileset_record(jcr, jcr->db, &fsr)) {
807       if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
808          Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
809             fsr.FileSet, db_strerror(jcr->db));
810          return false;
811       }
812    }
813    jcr->jr.FileSetId = fsr.FileSetId;
814    bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
815    Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
816       jcr->jr.FileSetId);
817    return true;
818 }
819
820 void init_jcr_job_record(JCR *jcr)
821 {
822    jcr->jr.SchedTime = jcr->sched_time;
823    jcr->jr.StartTime = jcr->start_time;
824    jcr->jr.EndTime = 0;               /* perhaps rescheduled, clear it */
825    jcr->jr.JobType = jcr->JobType;
826    jcr->jr.JobLevel = jcr->JobLevel;
827    jcr->jr.JobStatus = jcr->JobStatus;
828    jcr->jr.JobId = jcr->JobId;
829    bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
830    bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
831 }
832
833 /*
834  * Write status and such in DB
835  */
836 void update_job_end_record(JCR *jcr)
837 {
838    jcr->jr.EndTime = time(NULL);
839    jcr->end_time = jcr->jr.EndTime;
840    jcr->jr.JobId = jcr->JobId;
841    jcr->jr.JobStatus = jcr->JobStatus;
842    jcr->jr.JobFiles = jcr->JobFiles;
843    jcr->jr.JobBytes = jcr->JobBytes;
844    jcr->jr.VolSessionId = jcr->VolSessionId;
845    jcr->jr.VolSessionTime = jcr->VolSessionTime;
846    jcr->jr.JobErrors = jcr->Errors;
847    if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr, jcr->job->stats_enabled)) {
848       Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
849          db_strerror(jcr->db));
850    }
851 }
852
853 /*
854  * Takes base_name and appends (unique) current
855  *   date and time to form unique job name.
856  *
857  *  Note, the seconds are actually a sequence number. This
858  *   permits us to start a maximum fo 59 unique jobs a second, which
859  *   should be sufficient.
860  *
861  *  Returns: unique job name in jcr->Job
862  *    date/time in jcr->start_time
863  */
864 void create_unique_job_name(JCR *jcr, const char *base_name)
865 {
866    /* Job start mutex */
867    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
868    static time_t last_start_time = 0;
869    static int seq = 0;
870    time_t now;
871    struct tm tm;
872    char dt[MAX_TIME_LENGTH];
873    char name[MAX_NAME_LENGTH];
874    char *p;
875
876    /* Guarantee unique start time -- maximum one per second, and
877     * thus unique Job Name
878     */
879    P(mutex);                          /* lock creation of jobs */
880    now = time(NULL);
881    seq++;
882    if (seq > 59) {                    /* wrap as if it is seconds */
883       seq = 0;
884       while (now == last_start_time) {
885          bmicrosleep(0, 500000);
886          now = time(NULL);
887       }
888    }
889    last_start_time = now;
890    V(mutex);                          /* allow creation of jobs */
891    jcr->start_time = now;
892    /* Form Unique JobName */
893    (void)localtime_r(&now, &tm);
894    /* Use only characters that are permitted in Windows filenames */
895    strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
896    bstrncpy(name, base_name, sizeof(name));
897    name[sizeof(name)-22] = 0;          /* truncate if too long */
898    bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
899    /* Convert spaces into underscores */
900    for (p=jcr->Job; *p; p++) {
901       if (*p == ' ') {
902          *p = '_';
903       }
904    }
905 }
906
907 /* Called directly from job rescheduling */
908 void dird_free_jcr_pointers(JCR *jcr)
909 {
910    if (jcr->sd_auth_key) {
911       free(jcr->sd_auth_key);
912       jcr->sd_auth_key = NULL;
913    }
914    if (jcr->where) {
915       free(jcr->where);
916       jcr->where = NULL;
917    }
918    if (jcr->file_bsock) {
919       Dmsg0(200, "Close File bsock\n");
920       bnet_close(jcr->file_bsock);
921       jcr->file_bsock = NULL;
922    }
923    if (jcr->store_bsock) {
924       Dmsg0(200, "Close Store bsock\n");
925       bnet_close(jcr->store_bsock);
926       jcr->store_bsock = NULL;
927    }
928    if (jcr->fname) {
929       Dmsg0(200, "Free JCR fname\n");
930       free_pool_memory(jcr->fname);
931       jcr->fname = NULL;
932    }
933    if (jcr->RestoreBootstrap) {
934       free(jcr->RestoreBootstrap);
935       jcr->RestoreBootstrap = NULL;
936    }
937    if (jcr->client_uname) {
938       free_pool_memory(jcr->client_uname);
939       jcr->client_uname = NULL;
940    }
941    if (jcr->attr) {
942       free_pool_memory(jcr->attr);
943       jcr->attr = NULL;
944    }
945    if (jcr->ar) {
946       free(jcr->ar);
947       jcr->ar = NULL;
948    }
949 }
950
951 /*
952  * Free the Job Control Record if no one is still using it.
953  *  Called from main free_jcr() routine in src/lib/jcr.c so
954  *  that we can do our Director specific cleanup of the jcr.
955  */
956 void dird_free_jcr(JCR *jcr)
957 {
958    Dmsg0(200, "Start dird free_jcr\n");
959
960    dird_free_jcr_pointers(jcr);
961    if (jcr->term_wait_inited) {
962       pthread_cond_destroy(&jcr->term_wait);
963       jcr->term_wait_inited = false;
964    }
965    if (jcr->db_batch && jcr->db_batch != jcr->db) {
966       db_close_database(jcr, jcr->db_batch);
967    }
968    jcr->db_batch = NULL;
969    if (jcr->db) {
970       db_close_database(jcr, jcr->db);
971       jcr->db = NULL;
972    }
973    if (jcr->stime) {
974       Dmsg0(200, "Free JCR stime\n");
975       free_pool_memory(jcr->stime);
976       jcr->stime = NULL;
977    }
978    if (jcr->fname) {
979       Dmsg0(200, "Free JCR fname\n");
980       free_pool_memory(jcr->fname);
981       jcr->fname = NULL;
982    }
983    if (jcr->pool_source) {
984       free_pool_memory(jcr->pool_source);
985       jcr->pool_source = NULL;
986    }
987    if (jcr->catalog_source) {
988       free_pool_memory(jcr->catalog_source);
989       jcr->catalog_source = NULL;
990    }
991    if (jcr->rpool_source) {
992       free_pool_memory(jcr->rpool_source);
993       jcr->rpool_source = NULL;
994    }
995    if (jcr->wstore_source) {
996       free_pool_memory(jcr->wstore_source);
997       jcr->wstore_source = NULL;
998    }
999    if (jcr->rstore_source) {
1000       free_pool_memory(jcr->rstore_source);
1001       jcr->rstore_source = NULL;
1002    }
1003
1004    /* Delete lists setup to hold storage pointers */
1005    free_rwstorage(jcr);
1006
1007    jcr->job_end_push.destroy();
1008
1009    if (jcr->JobId != 0)
1010       write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1011
1012    Dmsg0(200, "End dird free_jcr\n");
1013 }
1014
1015 /* 
1016  * The Job storage definition must be either in the Job record
1017  *  or in the Pool record.  The Pool record overrides the Job 
1018  *  record.
1019  */
1020 void get_job_storage(USTORE *store, JOB *job, RUN *run) 
1021 {
1022    if (run && run->pool && run->pool->storage) {
1023       store->store = (STORE *)run->pool->storage->first();
1024       pm_strcpy(store->store_source, _("Run pool override"));
1025       return;
1026    }
1027    if (run && run->storage) {
1028       store->store = run->storage;
1029       pm_strcpy(store->store_source, _("Run storage override"));
1030       return;
1031    }
1032    if (job->pool->storage) {
1033       store->store = (STORE *)job->pool->storage->first();
1034       pm_strcpy(store->store_source, _("Pool resource"));
1035    } else {
1036       store->store = (STORE *)job->storage->first();
1037       pm_strcpy(store->store_source, _("Job resource"));
1038    }
1039 }
1040
1041 /*
1042  * Set some defaults in the JCR necessary to
1043  * run. These items are pulled from the job
1044  * definition as defaults, but can be overridden
1045  * later either by the Run record in the Schedule resource,
1046  * or by the Console program.
1047  */
1048 void set_jcr_defaults(JCR *jcr, JOB *job)
1049 {
1050    jcr->job = job;
1051    jcr->JobType = job->JobType;
1052    jcr->JobStatus = JS_Created;
1053    switch (jcr->JobType) {
1054    case JT_ADMIN:
1055       jcr->JobLevel = L_NONE;
1056       break;
1057    case JT_VERIFY:
1058    case JT_RESTORE:
1059    case JT_COPY:
1060    case JT_MIGRATE:
1061       jcr->JobReads = true;
1062       jcr->JobLevel = job->JobLevel;
1063       break;
1064    case JT_BACKUP:
1065       jcr->JobLevel = job->JobLevel;
1066       if (jcr->JobLevel == L_VIRTUAL_FULL) {
1067          jcr->JobReads = true;
1068       }
1069       break;
1070    default:
1071       jcr->JobLevel = job->JobLevel;
1072       break;
1073    }
1074    if (jcr->JobReads) {
1075       if (!jcr->rpool_source) {
1076          jcr->rpool_source = get_pool_memory(PM_MESSAGE);
1077          pm_strcpy(jcr->rpool_source, _("unknown source"));
1078       }
1079    }
1080    if (!jcr->fname) {
1081       jcr->fname = get_pool_memory(PM_FNAME);
1082    }
1083    if (!jcr->pool_source) {
1084       jcr->pool_source = get_pool_memory(PM_MESSAGE);
1085       pm_strcpy(jcr->pool_source, _("unknown source"));
1086    }
1087    if (!jcr->catalog_source) {
1088       jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1089       pm_strcpy(jcr->catalog_source, _("unknown source"));
1090    }
1091
1092    jcr->JobPriority = job->Priority;
1093    /* Copy storage definitions -- deleted in dir_free_jcr above */
1094    if (job->storage) {
1095       copy_rwstorage(jcr, job->storage, _("Job resource"));
1096    } else {
1097       copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1098    }
1099    jcr->client = job->client;
1100    if (!jcr->client_name) {
1101       jcr->client_name = get_pool_memory(PM_NAME);
1102    }
1103    pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1104    pm_strcpy(jcr->pool_source, _("Job resource"));
1105    jcr->pool = job->pool;
1106    jcr->full_pool = job->full_pool;
1107    jcr->inc_pool = job->inc_pool;
1108    jcr->diff_pool = job->diff_pool;
1109    if (job->pool->catalog) {
1110       jcr->catalog = job->pool->catalog;
1111       pm_strcpy(jcr->catalog_source, _("Pool resource"));
1112    } else {
1113       jcr->catalog = job->client->catalog;
1114       pm_strcpy(jcr->catalog_source, _("Client resource"));
1115    }
1116    jcr->fileset = job->fileset;
1117    jcr->messages = job->messages;
1118    jcr->spool_data = job->spool_data;
1119    jcr->spool_size = job->spool_size;
1120    jcr->write_part_after_job = job->write_part_after_job;
1121    jcr->accurate = job->accurate;
1122    if (jcr->RestoreBootstrap) {
1123       free(jcr->RestoreBootstrap);
1124       jcr->RestoreBootstrap = NULL;
1125    }
1126    /* This can be overridden by Console program */
1127    if (job->RestoreBootstrap) {
1128       jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1129    }
1130    /* This can be overridden by Console program */
1131    jcr->verify_job = job->verify_job;
1132    /* If no default level given, set one */
1133    if (jcr->JobLevel == 0) {
1134       switch (jcr->JobType) {
1135       case JT_VERIFY:
1136          jcr->JobLevel = L_VERIFY_CATALOG;
1137          break;
1138       case JT_BACKUP:
1139          jcr->JobLevel = L_INCREMENTAL;
1140          break;
1141       case JT_RESTORE:
1142       case JT_ADMIN:
1143          jcr->JobLevel = L_NONE;
1144          break;
1145       default:
1146          jcr->JobLevel = L_FULL;
1147          break;
1148       }
1149    }
1150 }
1151
1152 /* 
1153  * Copy the storage definitions from an alist to the JCR
1154  */
1155 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1156 {
1157    if (jcr->JobReads) {
1158       copy_rstorage(jcr, storage, where);
1159    } else {
1160       copy_wstorage(jcr, storage, where);
1161    }
1162 }
1163
1164
1165 /* Set storage override.  Releases any previous storage definition */
1166 void set_rwstorage(JCR *jcr, USTORE *store)
1167 {
1168    if (!store) {
1169       Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1170       return;
1171    }
1172    if (jcr->JobReads) {
1173       set_rstorage(jcr, store);
1174    } else {
1175       set_wstorage(jcr, store);
1176    }
1177 }
1178
1179 void free_rwstorage(JCR *jcr)
1180 {
1181    free_rstorage(jcr);
1182    free_wstorage(jcr);
1183 }
1184
1185 /* 
1186  * Copy the storage definitions from an alist to the JCR
1187  */
1188 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1189 {
1190    if (storage) {
1191       STORE *st;
1192       if (jcr->rstorage) {
1193          delete jcr->rstorage;
1194       }
1195       jcr->rstorage = New(alist(10, not_owned_by_alist));
1196       foreach_alist(st, storage) {
1197          jcr->rstorage->append(st);
1198       }
1199       if (!jcr->rstore_source) {
1200          jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1201       }
1202       pm_strcpy(jcr->rstore_source, where);
1203       if (jcr->rstorage) {
1204          jcr->rstore = (STORE *)jcr->rstorage->first();
1205       }
1206    }
1207 }
1208
1209
1210 /* Set storage override.  Remove all previous storage */
1211 void set_rstorage(JCR *jcr, USTORE *store)
1212 {
1213    STORE *storage;
1214
1215    if (!store->store) {
1216       return;
1217    }
1218    if (jcr->rstorage) {
1219       free_rstorage(jcr);
1220    }
1221    if (!jcr->rstorage) {
1222       jcr->rstorage = New(alist(10, not_owned_by_alist));
1223    }
1224    jcr->rstore = store->store;
1225    if (!jcr->rstore_source) {
1226       jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1227    }
1228    pm_strcpy(jcr->rstore_source, store->store_source);
1229    foreach_alist(storage, jcr->rstorage) {
1230       if (store->store == storage) {
1231          return;
1232       }
1233    }
1234    /* Store not in list, so add it */
1235    jcr->rstorage->prepend(store->store);
1236 }
1237
1238 void free_rstorage(JCR *jcr)
1239 {
1240    if (jcr->rstorage) {
1241       delete jcr->rstorage;
1242       jcr->rstorage = NULL;
1243    }
1244    jcr->rstore = NULL;
1245 }
1246
1247 /* 
1248  * Copy the storage definitions from an alist to the JCR
1249  */
1250 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1251 {
1252    if (storage) {
1253       STORE *st;
1254       if (jcr->wstorage) {
1255          delete jcr->wstorage;
1256       }
1257       jcr->wstorage = New(alist(10, not_owned_by_alist));
1258       foreach_alist(st, storage) {
1259          Dmsg1(100, "wstorage=%s\n", st->name());
1260          jcr->wstorage->append(st);
1261       }
1262       if (!jcr->wstore_source) {
1263          jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1264       }
1265       pm_strcpy(jcr->wstore_source, where);
1266       if (jcr->wstorage) {
1267          jcr->wstore = (STORE *)jcr->wstorage->first();
1268          Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1269       }
1270    }
1271 }
1272
1273
1274 /* Set storage override. Remove all previous storage */
1275 void set_wstorage(JCR *jcr, USTORE *store)
1276 {
1277    STORE *storage;
1278
1279    if (!store->store) {
1280       return;
1281    }
1282    if (jcr->wstorage) {
1283       free_wstorage(jcr);
1284    }
1285    if (!jcr->wstorage) {
1286       jcr->wstorage = New(alist(10, not_owned_by_alist));
1287    }
1288    jcr->wstore = store->store;
1289    if (!jcr->wstore_source) {
1290       jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1291    }
1292    pm_strcpy(jcr->wstore_source, store->store_source);
1293    Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1294    foreach_alist(storage, jcr->wstorage) {
1295       if (store->store == storage) {
1296          return;
1297       }
1298    }
1299    /* Store not in list, so add it */
1300    jcr->wstorage->prepend(store->store);
1301 }
1302
1303 void free_wstorage(JCR *jcr)
1304 {
1305    if (jcr->wstorage) {
1306       delete jcr->wstorage;
1307       jcr->wstorage = NULL;
1308    }
1309    jcr->wstore = NULL;
1310 }
1311
1312 char *job_code_callback_clones(JCR *jcr, const char* param) 
1313 {
1314    if (param[0] == 'p') {
1315       return jcr->pool->name();
1316    }
1317    return NULL;
1318 }
1319
1320 void create_clones(JCR *jcr)
1321 {
1322    /*
1323     * Fire off any clone jobs (run directives)
1324     */
1325    Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1326    if (!jcr->cloned && jcr->job->run_cmds) {
1327       char *runcmd;
1328       JOB *job = jcr->job;
1329       POOLMEM *cmd = get_pool_memory(PM_FNAME);
1330       UAContext *ua = new_ua_context(jcr);
1331       ua->batch = true;
1332       foreach_alist(runcmd, job->run_cmds) {
1333          cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1334          Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1335          Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1336          parse_ua_args(ua);                 /* parse command */
1337          int stat = run_cmd(ua, ua->cmd);
1338          if (stat == 0) {
1339             Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1340          } else {
1341             Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1342          }
1343       }
1344       free_ua_context(ua);
1345       free_pool_memory(cmd);
1346    }
1347 }
1348
1349 /*
1350  * Given: a JobId in jcr->previous_jr.JobId,
1351  *  this subroutine writes a bsr file to restore that job.
1352  */
1353 bool create_restore_bootstrap_file(JCR *jcr)
1354 {
1355    RESTORE_CTX rx;
1356    UAContext *ua;
1357    memset(&rx, 0, sizeof(rx));
1358    rx.bsr = new_bsr();
1359    rx.JobIds = (char *)"";                       
1360    rx.bsr->JobId = jcr->previous_jr.JobId;
1361    ua = new_ua_context(jcr);
1362    complete_bsr(ua, rx.bsr);
1363    rx.bsr->fi = new_findex();
1364    rx.bsr->fi->findex = 1;
1365    rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1366    jcr->ExpectedFiles = write_bsr_file(ua, rx);
1367    if (jcr->ExpectedFiles == 0) {
1368       free_ua_context(ua);
1369       free_bsr(rx.bsr);
1370       return false;
1371    }
1372    free_ua_context(ua);
1373    free_bsr(rx.bsr);
1374    jcr->needs_sd = true;
1375    return true;
1376 }
1377
1378 bool run_console_command(JCR *jcr, const char *cmd){
1379    UAContext *ua;
1380    bool ok;
1381
1382    ua = new_ua_context(jcr);
1383    Mmsg(ua->cmd, "%s", cmd);
1384    Dmsg1(100, "Console command: %s\n", ua->cmd);
1385    parse_ua_args(ua);
1386    ok= do_a_command(ua);
1387    free_ua_context(ua);
1388    return ok;
1389 }