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