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