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