]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/job.c
Cleanup function name and move MaxRunSchedTime value to JCR
[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
700    if (jcr->no_check_duplicates || 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    jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1172    if (jcr->RestoreBootstrap) {
1173       free(jcr->RestoreBootstrap);
1174       jcr->RestoreBootstrap = NULL;
1175    }
1176    /* This can be overridden by Console program */
1177    if (job->RestoreBootstrap) {
1178       jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1179    }
1180    /* This can be overridden by Console program */
1181    jcr->verify_job = job->verify_job;
1182    /* If no default level given, set one */
1183    if (jcr->getJobLevel() == 0) {
1184       switch (jcr->getJobType()) {
1185       case JT_VERIFY:
1186          jcr->setJobLevel(L_VERIFY_CATALOG);
1187          break;
1188       case JT_BACKUP:
1189          jcr->setJobLevel(L_INCREMENTAL);
1190          break;
1191       case JT_RESTORE:
1192       case JT_ADMIN:
1193          jcr->setJobLevel(L_NONE);
1194          break;
1195       default:
1196          jcr->setJobLevel(L_FULL);
1197          break;
1198       }
1199    }
1200 }
1201
1202 /* 
1203  * Copy the storage definitions from an alist to the JCR
1204  */
1205 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1206 {
1207    if (jcr->JobReads()) {
1208       copy_rstorage(jcr, storage, where);
1209    }
1210    copy_wstorage(jcr, storage, where);
1211 }
1212
1213
1214 /* Set storage override.  Releases any previous storage definition */
1215 void set_rwstorage(JCR *jcr, USTORE *store)
1216 {
1217    if (!store) {
1218       Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1219       return;
1220    }
1221    if (jcr->JobReads()) {
1222       set_rstorage(jcr, store);
1223    }
1224    set_wstorage(jcr, store);
1225 }
1226
1227 void free_rwstorage(JCR *jcr)
1228 {
1229    free_rstorage(jcr);
1230    free_wstorage(jcr);
1231 }
1232
1233 /* 
1234  * Copy the storage definitions from an alist to the JCR
1235  */
1236 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1237 {
1238    if (storage) {
1239       STORE *st;
1240       if (jcr->rstorage) {
1241          delete jcr->rstorage;
1242       }
1243       jcr->rstorage = New(alist(10, not_owned_by_alist));
1244       foreach_alist(st, storage) {
1245          jcr->rstorage->append(st);
1246       }
1247       if (!jcr->rstore_source) {
1248          jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1249       }
1250       pm_strcpy(jcr->rstore_source, where);
1251       if (jcr->rstorage) {
1252          jcr->rstore = (STORE *)jcr->rstorage->first();
1253       }
1254    }
1255 }
1256
1257
1258 /* Set storage override.  Remove all previous storage */
1259 void set_rstorage(JCR *jcr, USTORE *store)
1260 {
1261    STORE *storage;
1262
1263    if (!store->store) {
1264       return;
1265    }
1266    if (jcr->rstorage) {
1267       free_rstorage(jcr);
1268    }
1269    if (!jcr->rstorage) {
1270       jcr->rstorage = New(alist(10, not_owned_by_alist));
1271    }
1272    jcr->rstore = store->store;
1273    if (!jcr->rstore_source) {
1274       jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1275    }
1276    pm_strcpy(jcr->rstore_source, store->store_source);
1277    foreach_alist(storage, jcr->rstorage) {
1278       if (store->store == storage) {
1279          return;
1280       }
1281    }
1282    /* Store not in list, so add it */
1283    jcr->rstorage->prepend(store->store);
1284 }
1285
1286 void free_rstorage(JCR *jcr)
1287 {
1288    if (jcr->rstorage) {
1289       delete jcr->rstorage;
1290       jcr->rstorage = NULL;
1291    }
1292    jcr->rstore = NULL;
1293 }
1294
1295 /* 
1296  * Copy the storage definitions from an alist to the JCR
1297  */
1298 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1299 {
1300    if (storage) {
1301       STORE *st;
1302       if (jcr->wstorage) {
1303          delete jcr->wstorage;
1304       }
1305       jcr->wstorage = New(alist(10, not_owned_by_alist));
1306       foreach_alist(st, storage) {
1307          Dmsg1(100, "wstorage=%s\n", st->name());
1308          jcr->wstorage->append(st);
1309       }
1310       if (!jcr->wstore_source) {
1311          jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1312       }
1313       pm_strcpy(jcr->wstore_source, where);
1314       if (jcr->wstorage) {
1315          jcr->wstore = (STORE *)jcr->wstorage->first();
1316          Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1317       }
1318    }
1319 }
1320
1321
1322 /* Set storage override. Remove all previous storage */
1323 void set_wstorage(JCR *jcr, USTORE *store)
1324 {
1325    STORE *storage;
1326
1327    if (!store->store) {
1328       return;
1329    }
1330    if (jcr->wstorage) {
1331       free_wstorage(jcr);
1332    }
1333    if (!jcr->wstorage) {
1334       jcr->wstorage = New(alist(10, not_owned_by_alist));
1335    }
1336    jcr->wstore = store->store;
1337    if (!jcr->wstore_source) {
1338       jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1339    }
1340    pm_strcpy(jcr->wstore_source, store->store_source);
1341    Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1342    foreach_alist(storage, jcr->wstorage) {
1343       if (store->store == storage) {
1344          return;
1345       }
1346    }
1347    /* Store not in list, so add it */
1348    jcr->wstorage->prepend(store->store);
1349 }
1350
1351 void free_wstorage(JCR *jcr)
1352 {
1353    if (jcr->wstorage) {
1354       delete jcr->wstorage;
1355       jcr->wstorage = NULL;
1356    }
1357    jcr->wstore = NULL;
1358 }
1359
1360 char *job_code_callback_clones(JCR *jcr, const char* param) 
1361 {
1362    if (param[0] == 'p') {
1363       return jcr->pool->name();
1364    }
1365    return NULL;
1366 }
1367
1368 void create_clones(JCR *jcr)
1369 {
1370    /*
1371     * Fire off any clone jobs (run directives)
1372     */
1373    Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1374    if (!jcr->cloned && jcr->job->run_cmds) {
1375       char *runcmd;
1376       JOB *job = jcr->job;
1377       POOLMEM *cmd = get_pool_memory(PM_FNAME);
1378       UAContext *ua = new_ua_context(jcr);
1379       ua->batch = true;
1380       foreach_alist(runcmd, job->run_cmds) {
1381          cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1382          Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1383          Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1384          parse_ua_args(ua);                 /* parse command */
1385          int stat = run_cmd(ua, ua->cmd);
1386          if (stat == 0) {
1387             Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1388                  ua->cmd);
1389          } else {
1390             Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1391          }
1392       }
1393       free_ua_context(ua);
1394       free_pool_memory(cmd);
1395    }
1396 }
1397
1398 /*
1399  * Given: a JobId in jcr->previous_jr.JobId,
1400  *  this subroutine writes a bsr file to restore that job.
1401  * Returns: -1 on error
1402  *           number of files if OK
1403  */
1404 int create_restore_bootstrap_file(JCR *jcr)
1405 {
1406    RESTORE_CTX rx;
1407    UAContext *ua;
1408    int files;
1409
1410    memset(&rx, 0, sizeof(rx));
1411    rx.bsr = new_bsr();
1412    rx.JobIds = (char *)"";                       
1413    rx.bsr->JobId = jcr->previous_jr.JobId;
1414    ua = new_ua_context(jcr);
1415    if (!complete_bsr(ua, rx.bsr)) {
1416       files = -1;
1417       goto bail_out;
1418    }
1419    rx.bsr->fi = new_findex();
1420    rx.bsr->fi->findex = 1;
1421    rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1422    jcr->ExpectedFiles = write_bsr_file(ua, rx);
1423    if (jcr->ExpectedFiles == 0) {
1424       files = 0;
1425       goto bail_out;
1426    }
1427    free_ua_context(ua);
1428    free_bsr(rx.bsr);
1429    jcr->needs_sd = true;
1430    return jcr->ExpectedFiles;
1431
1432 bail_out:
1433    free_ua_context(ua);
1434    free_bsr(rx.bsr);
1435    return files;
1436 }
1437
1438 /* TODO: redirect command ouput to job log */
1439 bool run_console_command(JCR *jcr, const char *cmd)
1440 {
1441    UAContext *ua;
1442    bool ok;
1443    JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1444    ua = new_ua_context(ljcr);
1445    /* run from runscript and check if commands are autorized */
1446    ua->runscript = true;
1447    Mmsg(ua->cmd, "%s", cmd);
1448    Dmsg1(100, "Console command: %s\n", ua->cmd);
1449    parse_ua_args(ua);
1450    ok= do_a_command(ua);
1451    free_ua_context(ua);
1452    free_jcr(ljcr);
1453    return ok;
1454 }