]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/job.c
replace set_Jobxxx by setJobxxx
[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_maxschedruntime(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    sm_check(__FILE__, __LINE__, true);
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(1);
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(1);
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_maxschedruntime(jcr)) {
276       jcr->setJobStatus(JS_Canceled);
277       Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run 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    sm_check(__FILE__, __LINE__, true);
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(1);
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_maxschedruntime(jcr)) {
557          jcr->setJobStatus(JS_Canceled);
558          Qmsg(jcr, M_FATAL, 0, _("Max sched run 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_maxschedruntime(JCR *jcr)
651 {
652    if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
653       return false;
654    }
655    if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
656       Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
657             jcr, jcr->Job, jcr->job->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
700    if (job->AllowDuplicateJobs) {
701       return true;
702    }
703    Dmsg0(800, "Enter allow_duplicate_job\n");
704    /*
705     * After this point, we do not want to allow any duplicate
706     * job to run.
707     */
708
709    foreach_jcr(djcr) {
710       if (jcr == djcr || djcr->JobId == 0) {
711          continue;                   /* do not cancel this job or consoles */
712       }
713       if (strcmp(job->name(), djcr->job->name()) == 0) {
714          bool cancel_dup = false;
715          bool cancel_me = false; 
716          if (job->DuplicateJobProximity > 0) {
717             utime_t now = (utime_t)time(NULL);
718             if ((now - djcr->start_time) > job->DuplicateJobProximity) {
719                continue;               /* not really a duplicate */
720             }
721          }
722          if (job->CancelLowerLevelDuplicates &&                         
723              djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
724             switch (jcr->getJobLevel()) {
725             case L_FULL:
726                if (djcr->getJobLevel() == L_DIFFERENTIAL ||
727                    djcr->getJobLevel() == L_INCREMENTAL) {
728                   cancel_dup = true;
729                }
730                break;
731             case L_DIFFERENTIAL:
732                if (djcr->getJobLevel() == L_INCREMENTAL) {
733                   cancel_dup = true;
734                }
735                if (djcr->getJobLevel() == L_FULL) {
736                   cancel_me = true;
737                }
738                break;
739             case L_INCREMENTAL:
740                if (djcr->getJobLevel() == L_FULL ||
741                    djcr->getJobLevel() == L_DIFFERENTIAL) {
742                   cancel_me = true;
743                }
744             }
745             /*
746              * cancel_dup will be done below   
747              */
748             if (cancel_me) {
749               /* Zap current job */
750               Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
751                  djcr->JobId);
752               break;     /* get out of foreach_jcr */
753             }
754          }   
755          /* Cancel one of the two jobs (me or dup) */
756          /* If CancelQueuedDuplicates is set do so only if job is queued */
757          if (job->CancelQueuedDuplicates) {
758              switch (djcr->JobStatus) {
759              case JS_Created:
760              case JS_WaitJobRes:
761              case JS_WaitClientRes:
762              case JS_WaitStoreRes:
763              case JS_WaitPriority:
764              case JS_WaitMaxJobs:
765              case JS_WaitStartTime:
766                 cancel_dup = true;  /* cancel queued duplicate */
767                 break;
768              default:
769                 break;
770              }
771          }
772          if (cancel_dup || job->CancelRunningDuplicates) {
773             /* Zap the duplicated job djcr */
774             UAContext *ua = new_ua_context(jcr);
775             Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
776             cancel_job(ua, djcr);
777             bmicrosleep(0, 500000);
778             cancel_job(ua, djcr);
779             free_ua_context(ua);
780             Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
781          } else {
782             /* Zap current job */
783             Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
784                djcr->JobId);
785             Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
786          }
787          Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
788                jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
789          break;                 /* did our work, get out of foreach loop */
790       }
791    }
792    endeach_jcr(djcr);
793
794    return true;   
795 }
796
797 void apply_pool_overrides(JCR *jcr)
798 {
799    bool pool_override = false;
800
801    if (jcr->run_pool_override) {
802       pm_strcpy(jcr->pool_source, _("Run pool override"));
803    }
804    /*
805     * Apply any level related Pool selections
806     */
807    switch (jcr->getJobLevel()) {
808    case L_FULL:
809       if (jcr->full_pool) {
810          jcr->pool = jcr->full_pool;
811          pool_override = true;
812          if (jcr->run_full_pool_override) {
813             pm_strcpy(jcr->pool_source, _("Run FullPool override"));
814          } else {
815             pm_strcpy(jcr->pool_source, _("Job FullPool override"));
816          }
817       }
818       break;
819    case L_INCREMENTAL:
820       if (jcr->inc_pool) {
821          jcr->pool = jcr->inc_pool;
822          pool_override = true;
823          if (jcr->run_inc_pool_override) {
824             pm_strcpy(jcr->pool_source, _("Run IncPool override"));
825          } else {
826             pm_strcpy(jcr->pool_source, _("Job IncPool override"));
827          }
828       }
829       break;
830    case L_DIFFERENTIAL:
831       if (jcr->diff_pool) {
832          jcr->pool = jcr->diff_pool;
833          pool_override = true;
834          if (jcr->run_diff_pool_override) {
835             pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
836          } else {
837             pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
838          }
839       }
840       break;
841    }
842    /* Update catalog if pool overridden */
843    if (pool_override && jcr->pool->catalog) {
844       jcr->catalog = jcr->pool->catalog;
845       pm_strcpy(jcr->catalog_source, _("Pool resource"));
846    }
847 }
848
849
850 /*
851  * Get or create a Client record for this Job
852  */
853 bool get_or_create_client_record(JCR *jcr)
854 {
855    CLIENT_DBR cr;
856
857    memset(&cr, 0, sizeof(cr));
858    bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
859    cr.AutoPrune = jcr->client->AutoPrune;
860    cr.FileRetention = jcr->client->FileRetention;
861    cr.JobRetention = jcr->client->JobRetention;
862    if (!jcr->client_name) {
863       jcr->client_name = get_pool_memory(PM_NAME);
864    }
865    pm_strcpy(jcr->client_name, jcr->client->hdr.name);
866    if (!db_create_client_record(jcr, jcr->db, &cr)) {
867       Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
868          db_strerror(jcr->db));
869       return false;
870    }
871    jcr->jr.ClientId = cr.ClientId;
872    if (cr.Uname[0]) {
873       if (!jcr->client_uname) {
874          jcr->client_uname = get_pool_memory(PM_NAME);
875       }
876       pm_strcpy(jcr->client_uname, cr.Uname);
877    }
878    Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
879       jcr->jr.ClientId);
880    return true;
881 }
882
883 bool get_or_create_fileset_record(JCR *jcr)
884 {
885    FILESET_DBR fsr;
886    /*
887     * Get or Create FileSet record
888     */
889    memset(&fsr, 0, sizeof(FILESET_DBR));
890    bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
891    if (jcr->fileset->have_MD5) {
892       struct MD5Context md5c;
893       unsigned char digest[MD5HashSize];
894       memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
895       MD5Final(digest, &md5c);
896       /*
897        * Keep the flag (last arg) set to false otherwise old FileSets will
898        * get new MD5 sums and the user will get Full backups on everything
899        */
900       bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
901       bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
902    } else {
903       Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
904    }
905    if (!jcr->fileset->ignore_fs_changes ||
906        !db_get_fileset_record(jcr, jcr->db, &fsr)) {
907       if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
908          Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
909             fsr.FileSet, db_strerror(jcr->db));
910          return false;
911       }
912    }
913    jcr->jr.FileSetId = fsr.FileSetId;
914    bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
915    Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
916       jcr->jr.FileSetId);
917    return true;
918 }
919
920 void init_jcr_job_record(JCR *jcr)
921 {
922    jcr->jr.SchedTime = jcr->sched_time;
923    jcr->jr.StartTime = jcr->start_time;
924    jcr->jr.EndTime = 0;               /* perhaps rescheduled, clear it */
925    jcr->jr.JobType = jcr->getJobType();
926    jcr->jr.JobLevel = jcr->getJobLevel();
927    jcr->jr.JobStatus = jcr->JobStatus;
928    jcr->jr.JobId = jcr->JobId;
929    bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
930    bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
931 }
932
933 /*
934  * Write status and such in DB
935  */
936 void update_job_end_record(JCR *jcr)
937 {
938    jcr->jr.EndTime = time(NULL);
939    jcr->end_time = jcr->jr.EndTime;
940    jcr->jr.JobId = jcr->JobId;
941    jcr->jr.JobStatus = jcr->JobStatus;
942    jcr->jr.JobFiles = jcr->JobFiles;
943    jcr->jr.JobBytes = jcr->JobBytes;
944    jcr->jr.ReadBytes = jcr->ReadBytes;
945    jcr->jr.VolSessionId = jcr->VolSessionId;
946    jcr->jr.VolSessionTime = jcr->VolSessionTime;
947    jcr->jr.JobErrors = jcr->JobErrors;
948    jcr->jr.HasBase = jcr->HasBase;
949    if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
950       Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
951          db_strerror(jcr->db));
952    }
953 }
954
955 /*
956  * Takes base_name and appends (unique) current
957  *   date and time to form unique job name.
958  *
959  *  Note, the seconds are actually a sequence number. This
960  *   permits us to start a maximum fo 59 unique jobs a second, which
961  *   should be sufficient.
962  *
963  *  Returns: unique job name in jcr->Job
964  *    date/time in jcr->start_time
965  */
966 void create_unique_job_name(JCR *jcr, const char *base_name)
967 {
968    /* Job start mutex */
969    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
970    static time_t last_start_time = 0;
971    static int seq = 0;
972    time_t now = time(NULL);
973    struct tm tm;
974    char dt[MAX_TIME_LENGTH];
975    char name[MAX_NAME_LENGTH];
976    char *p;
977    int len;
978
979    /* Guarantee unique start time -- maximum one per second, and
980     * thus unique Job Name
981     */
982    P(mutex);                          /* lock creation of jobs */
983    seq++;
984    if (seq > 59) {                    /* wrap as if it is seconds */
985       seq = 0;
986       while (now == last_start_time) {
987          bmicrosleep(0, 500000);
988          now = time(NULL);
989       }
990    }
991    last_start_time = now;
992    V(mutex);                          /* allow creation of jobs */
993    jcr->start_time = now;
994    /* Form Unique JobName */
995    (void)localtime_r(&now, &tm);
996    /* Use only characters that are permitted in Windows filenames */
997    strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
998    len = strlen(dt) + 5;   /* dt + .%02d EOS */
999    bstrncpy(name, base_name, sizeof(name));
1000    name[sizeof(name)-len] = 0;          /* truncate if too long */
1001    bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
1002    /* Convert spaces into underscores */
1003    for (p=jcr->Job; *p; p++) {
1004       if (*p == ' ') {
1005          *p = '_';
1006       }
1007    }
1008    Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1009 }
1010
1011 /* Called directly from job rescheduling */
1012 void dird_free_jcr_pointers(JCR *jcr)
1013 {
1014    if (jcr->file_bsock) {
1015       Dmsg0(200, "Close File bsock\n");
1016       bnet_close(jcr->file_bsock);
1017       jcr->file_bsock = NULL;
1018    }
1019    if (jcr->store_bsock) {
1020       Dmsg0(200, "Close Store bsock\n");
1021       bnet_close(jcr->store_bsock);
1022       jcr->store_bsock = NULL;
1023    }
1024
1025    bfree_and_null(jcr->sd_auth_key);
1026    bfree_and_null(jcr->where);
1027    bfree_and_null(jcr->RestoreBootstrap);
1028    bfree_and_null(jcr->ar);
1029
1030    free_and_null_pool_memory(jcr->JobIds);
1031    free_and_null_pool_memory(jcr->client_uname);
1032    free_and_null_pool_memory(jcr->attr);
1033    free_and_null_pool_memory(jcr->fname);
1034 }
1035
1036 /*
1037  * Free the Job Control Record if no one is still using it.
1038  *  Called from main free_jcr() routine in src/lib/jcr.c so
1039  *  that we can do our Director specific cleanup of the jcr.
1040  */
1041 void dird_free_jcr(JCR *jcr)
1042 {
1043    Dmsg0(200, "Start dird free_jcr\n");
1044
1045    dird_free_jcr_pointers(jcr);
1046    if (jcr->term_wait_inited) {
1047       pthread_cond_destroy(&jcr->term_wait);
1048       jcr->term_wait_inited = false;
1049    }
1050    if (jcr->db_batch) {
1051       db_close_database(jcr, jcr->db_batch);
1052       jcr->db_batch = NULL;
1053       jcr->batch_started = false;
1054    }
1055    if (jcr->db) {
1056       db_close_database(jcr, jcr->db);
1057       jcr->db = NULL;
1058    }
1059
1060    free_and_null_pool_memory(jcr->stime);
1061    free_and_null_pool_memory(jcr->fname);
1062    free_and_null_pool_memory(jcr->pool_source);
1063    free_and_null_pool_memory(jcr->catalog_source);
1064    free_and_null_pool_memory(jcr->rpool_source);
1065    free_and_null_pool_memory(jcr->wstore_source);
1066    free_and_null_pool_memory(jcr->rstore_source);
1067
1068    /* Delete lists setup to hold storage pointers */
1069    free_rwstorage(jcr);
1070
1071    jcr->job_end_push.destroy();
1072
1073    if (jcr->JobId != 0)
1074       write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1075
1076    free_plugins(jcr);                 /* release instantiated plugins */
1077
1078    Dmsg0(200, "End dird free_jcr\n");
1079 }
1080
1081 /* 
1082  * The Job storage definition must be either in the Job record
1083  *  or in the Pool record.  The Pool record overrides the Job 
1084  *  record.
1085  */
1086 void get_job_storage(USTORE *store, JOB *job, RUN *run) 
1087 {
1088    if (run && run->pool && run->pool->storage) {
1089       store->store = (STORE *)run->pool->storage->first();
1090       pm_strcpy(store->store_source, _("Run pool override"));
1091       return;
1092    }
1093    if (run && run->storage) {
1094       store->store = run->storage;
1095       pm_strcpy(store->store_source, _("Run storage override"));
1096       return;
1097    }
1098    if (job->pool->storage) {
1099       store->store = (STORE *)job->pool->storage->first();
1100       pm_strcpy(store->store_source, _("Pool resource"));
1101    } else {
1102       store->store = (STORE *)job->storage->first();
1103       pm_strcpy(store->store_source, _("Job resource"));
1104    }
1105 }
1106
1107 /*
1108  * Set some defaults in the JCR necessary to
1109  * run. These items are pulled from the job
1110  * definition as defaults, but can be overridden
1111  * later either by the Run record in the Schedule resource,
1112  * or by the Console program.
1113  */
1114 void set_jcr_defaults(JCR *jcr, JOB *job)
1115 {
1116    jcr->job = job;
1117    jcr->setJobType(job->JobType);
1118    jcr->JobStatus = JS_Created;
1119
1120    switch (jcr->getJobType()) {
1121    case JT_ADMIN:
1122       jcr->setJobLevel(L_NONE);
1123       break;
1124    default:
1125       jcr->setJobLevel(job->JobLevel);
1126       break;
1127    }
1128
1129    if (!jcr->fname) {
1130       jcr->fname = get_pool_memory(PM_FNAME);
1131    }
1132    if (!jcr->pool_source) {
1133       jcr->pool_source = get_pool_memory(PM_MESSAGE);
1134       pm_strcpy(jcr->pool_source, _("unknown source"));
1135    }
1136    if (!jcr->catalog_source) {
1137       jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1138       pm_strcpy(jcr->catalog_source, _("unknown source"));
1139    }
1140
1141    jcr->JobPriority = job->Priority;
1142    /* Copy storage definitions -- deleted in dir_free_jcr above */
1143    if (job->storage) {
1144       copy_rwstorage(jcr, job->storage, _("Job resource"));
1145    } else {
1146       copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1147    }
1148    jcr->client = job->client;
1149    if (!jcr->client_name) {
1150       jcr->client_name = get_pool_memory(PM_NAME);
1151    }
1152    pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1153    pm_strcpy(jcr->pool_source, _("Job resource"));
1154    jcr->pool = job->pool;
1155    jcr->full_pool = job->full_pool;
1156    jcr->inc_pool = job->inc_pool;
1157    jcr->diff_pool = job->diff_pool;
1158    if (job->pool->catalog) {
1159       jcr->catalog = job->pool->catalog;
1160       pm_strcpy(jcr->catalog_source, _("Pool resource"));
1161    } else {
1162       jcr->catalog = job->client->catalog;
1163       pm_strcpy(jcr->catalog_source, _("Client resource"));
1164    }
1165    jcr->fileset = job->fileset;
1166    jcr->messages = job->messages;
1167    jcr->spool_data = job->spool_data;
1168    jcr->spool_size = job->spool_size;
1169    jcr->write_part_after_job = job->write_part_after_job;
1170    jcr->accurate = job->accurate;
1171    if (jcr->RestoreBootstrap) {
1172       free(jcr->RestoreBootstrap);
1173       jcr->RestoreBootstrap = NULL;
1174    }
1175    /* This can be overridden by Console program */
1176    if (job->RestoreBootstrap) {
1177       jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1178    }
1179    /* This can be overridden by Console program */
1180    jcr->verify_job = job->verify_job;
1181    /* If no default level given, set one */
1182    if (jcr->getJobLevel() == 0) {
1183       switch (jcr->getJobType()) {
1184       case JT_VERIFY:
1185          jcr->setJobLevel(L_VERIFY_CATALOG);
1186          break;
1187       case JT_BACKUP:
1188          jcr->setJobLevel(L_INCREMENTAL);
1189          break;
1190       case JT_RESTORE:
1191       case JT_ADMIN:
1192          jcr->setJobLevel(L_NONE);
1193          break;
1194       default:
1195          jcr->setJobLevel(L_FULL);
1196          break;
1197       }
1198    }
1199 }
1200
1201 /* 
1202  * Copy the storage definitions from an alist to the JCR
1203  */
1204 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1205 {
1206    if (jcr->JobReads()) {
1207       copy_rstorage(jcr, storage, where);
1208    }
1209    copy_wstorage(jcr, storage, where);
1210 }
1211
1212
1213 /* Set storage override.  Releases any previous storage definition */
1214 void set_rwstorage(JCR *jcr, USTORE *store)
1215 {
1216    if (!store) {
1217       Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1218       return;
1219    }
1220    if (jcr->JobReads()) {
1221       set_rstorage(jcr, store);
1222    }
1223    set_wstorage(jcr, store);
1224 }
1225
1226 void free_rwstorage(JCR *jcr)
1227 {
1228    free_rstorage(jcr);
1229    free_wstorage(jcr);
1230 }
1231
1232 /* 
1233  * Copy the storage definitions from an alist to the JCR
1234  */
1235 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1236 {
1237    if (storage) {
1238       STORE *st;
1239       if (jcr->rstorage) {
1240          delete jcr->rstorage;
1241       }
1242       jcr->rstorage = New(alist(10, not_owned_by_alist));
1243       foreach_alist(st, storage) {
1244          jcr->rstorage->append(st);
1245       }
1246       if (!jcr->rstore_source) {
1247          jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1248       }
1249       pm_strcpy(jcr->rstore_source, where);
1250       if (jcr->rstorage) {
1251          jcr->rstore = (STORE *)jcr->rstorage->first();
1252       }
1253    }
1254 }
1255
1256
1257 /* Set storage override.  Remove all previous storage */
1258 void set_rstorage(JCR *jcr, USTORE *store)
1259 {
1260    STORE *storage;
1261
1262    if (!store->store) {
1263       return;
1264    }
1265    if (jcr->rstorage) {
1266       free_rstorage(jcr);
1267    }
1268    if (!jcr->rstorage) {
1269       jcr->rstorage = New(alist(10, not_owned_by_alist));
1270    }
1271    jcr->rstore = store->store;
1272    if (!jcr->rstore_source) {
1273       jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1274    }
1275    pm_strcpy(jcr->rstore_source, store->store_source);
1276    foreach_alist(storage, jcr->rstorage) {
1277       if (store->store == storage) {
1278          return;
1279       }
1280    }
1281    /* Store not in list, so add it */
1282    jcr->rstorage->prepend(store->store);
1283 }
1284
1285 void free_rstorage(JCR *jcr)
1286 {
1287    if (jcr->rstorage) {
1288       delete jcr->rstorage;
1289       jcr->rstorage = NULL;
1290    }
1291    jcr->rstore = NULL;
1292 }
1293
1294 /* 
1295  * Copy the storage definitions from an alist to the JCR
1296  */
1297 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1298 {
1299    if (storage) {
1300       STORE *st;
1301       if (jcr->wstorage) {
1302          delete jcr->wstorage;
1303       }
1304       jcr->wstorage = New(alist(10, not_owned_by_alist));
1305       foreach_alist(st, storage) {
1306          Dmsg1(100, "wstorage=%s\n", st->name());
1307          jcr->wstorage->append(st);
1308       }
1309       if (!jcr->wstore_source) {
1310          jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1311       }
1312       pm_strcpy(jcr->wstore_source, where);
1313       if (jcr->wstorage) {
1314          jcr->wstore = (STORE *)jcr->wstorage->first();
1315          Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1316       }
1317    }
1318 }
1319
1320
1321 /* Set storage override. Remove all previous storage */
1322 void set_wstorage(JCR *jcr, USTORE *store)
1323 {
1324    STORE *storage;
1325
1326    if (!store->store) {
1327       return;
1328    }
1329    if (jcr->wstorage) {
1330       free_wstorage(jcr);
1331    }
1332    if (!jcr->wstorage) {
1333       jcr->wstorage = New(alist(10, not_owned_by_alist));
1334    }
1335    jcr->wstore = store->store;
1336    if (!jcr->wstore_source) {
1337       jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1338    }
1339    pm_strcpy(jcr->wstore_source, store->store_source);
1340    Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1341    foreach_alist(storage, jcr->wstorage) {
1342       if (store->store == storage) {
1343          return;
1344       }
1345    }
1346    /* Store not in list, so add it */
1347    jcr->wstorage->prepend(store->store);
1348 }
1349
1350 void free_wstorage(JCR *jcr)
1351 {
1352    if (jcr->wstorage) {
1353       delete jcr->wstorage;
1354       jcr->wstorage = NULL;
1355    }
1356    jcr->wstore = NULL;
1357 }
1358
1359 char *job_code_callback_clones(JCR *jcr, const char* param) 
1360 {
1361    if (param[0] == 'p') {
1362       return jcr->pool->name();
1363    }
1364    return NULL;
1365 }
1366
1367 void create_clones(JCR *jcr)
1368 {
1369    /*
1370     * Fire off any clone jobs (run directives)
1371     */
1372    Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1373    if (!jcr->cloned && jcr->job->run_cmds) {
1374       char *runcmd;
1375       JOB *job = jcr->job;
1376       POOLMEM *cmd = get_pool_memory(PM_FNAME);
1377       UAContext *ua = new_ua_context(jcr);
1378       ua->batch = true;
1379       foreach_alist(runcmd, job->run_cmds) {
1380          cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1381          Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1382          Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1383          parse_ua_args(ua);                 /* parse command */
1384          int stat = run_cmd(ua, ua->cmd);
1385          if (stat == 0) {
1386             Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1387                  ua->cmd);
1388          } else {
1389             Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1390          }
1391       }
1392       free_ua_context(ua);
1393       free_pool_memory(cmd);
1394    }
1395 }
1396
1397 /*
1398  * Given: a JobId in jcr->previous_jr.JobId,
1399  *  this subroutine writes a bsr file to restore that job.
1400  * Returns: -1 on error
1401  *           number of files if OK
1402  */
1403 int create_restore_bootstrap_file(JCR *jcr)
1404 {
1405    RESTORE_CTX rx;
1406    UAContext *ua;
1407    int files;
1408
1409    memset(&rx, 0, sizeof(rx));
1410    rx.bsr = new_bsr();
1411    rx.JobIds = (char *)"";                       
1412    rx.bsr->JobId = jcr->previous_jr.JobId;
1413    ua = new_ua_context(jcr);
1414    if (!complete_bsr(ua, rx.bsr)) {
1415       files = -1;
1416       goto bail_out;
1417    }
1418    rx.bsr->fi = new_findex();
1419    rx.bsr->fi->findex = 1;
1420    rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1421    jcr->ExpectedFiles = write_bsr_file(ua, rx);
1422    if (jcr->ExpectedFiles == 0) {
1423       files = 0;
1424       goto bail_out;
1425    }
1426    free_ua_context(ua);
1427    free_bsr(rx.bsr);
1428    jcr->needs_sd = true;
1429    return jcr->ExpectedFiles;
1430
1431 bail_out:
1432    free_ua_context(ua);
1433    free_bsr(rx.bsr);
1434    return files;
1435 }
1436
1437 /* TODO: redirect command ouput to job log */
1438 bool run_console_command(JCR *jcr, const char *cmd)
1439 {
1440    UAContext *ua;
1441    bool ok;
1442    JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1443    ua = new_ua_context(ljcr);
1444    /* run from runscript and check if commands are autorized */
1445    ua->runscript = true;
1446    Mmsg(ua->cmd, "%s", cmd);
1447    Dmsg1(100, "Console command: %s\n", ua->cmd);
1448    parse_ua_args(ua);
1449    ok= do_a_command(ua);
1450    free_ua_context(ua);
1451    free_jcr(ljcr);
1452    return ok;
1453 }