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