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