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