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