]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/job.c
1d3fd12096251f74e4319a9930eca6ebddcf410b
[bacula/bacula] / bacula / src / dird / job.c
1 /*
2  *
3  *   Bacula Director Job processing routines
4  *
5  *     Kern Sibbald, October MM
6  *
7  *    Version $Id$
8  */
9 /*
10    Copyright (C) 2000-2003 Kern Sibbald and John Walker
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "dird.h"
31
32 /* Forward referenced subroutines */
33 static void *job_thread(void *arg);
34 static void job_monitor_watchdog(watchdog_t *self);
35 static void job_monitor_destructor(watchdog_t *self);
36 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr);
37 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr);
38
39 /* Exported subroutines */
40
41 /* Imported subroutines */
42 extern void term_scheduler();
43 extern void term_ua_server();
44 extern int do_backup(JCR *jcr);
45 extern int do_admin(JCR *jcr);
46 extern int do_restore(JCR *jcr);
47 extern int do_verify(JCR *jcr);
48
49 /* Imported variables */
50 extern time_t watchdog_time;
51
52 jobq_t  job_queue;
53
54 void init_job_server(int max_workers)
55 {
56    int stat;
57    watchdog_t *wd;
58    
59    if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
60       Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), strerror(stat));
61    }
62    if ((wd = watchdog_new()) == NULL) {
63       Emsg0(M_ABORT, 0, _("Could not init job monitor watchdogs\n"));
64    }
65    wd->callback = job_monitor_watchdog;
66    wd->destructor = job_monitor_destructor;
67    wd->one_shot = false;
68    wd->interval = 60;
69    wd->data = create_control_jcr("*JobMonitor*", JT_SYSTEM);
70    register_watchdog(wd);
71    
72    return;
73 }
74
75 static void job_monitor_destructor(watchdog_t *self)
76 {
77    JCR *control_jcr = (JCR *) self->data;
78
79    free_jcr(control_jcr);
80 }
81
82 static void job_monitor_watchdog(watchdog_t *self)
83 {
84    JCR *control_jcr, *jcr;
85
86    control_jcr = (JCR *) self->data;
87
88    Dmsg1(200, "job_monitor_watchdog %p called\n", self);
89
90    lock_jcr_chain();
91
92    for (jcr = NULL; (jcr = get_next_jcr(jcr)); /* nothing */) {
93       bool cancel;
94
95       if (jcr->JobId == 0) {
96          Dmsg2(200, "Skipping JCR %p (%s) with JobId 0\n",
97                jcr, jcr->Job);
98          /* Keep reference counts correct */
99          free_locked_jcr(jcr);
100          continue;
101       }
102
103       /* check MaxWaitTime */
104       cancel = job_check_maxwaittime(control_jcr, jcr);
105
106       /* check MaxRunTime */
107       cancel |= job_check_maxruntime(control_jcr, jcr);
108
109       if (cancel) {
110          Dmsg3(200, "Cancelling JCR %p jobid %d (%s)\n",
111                jcr, jcr->JobId, jcr->Job);
112
113          UAContext *ua = new_ua_context(jcr);
114          ua->jcr = control_jcr;
115          cancel_job(ua, jcr);
116          free_ua_context(ua);
117
118          Dmsg1(200, "Have cancelled JCR %p\n", jcr);
119       }
120
121       /* Keep reference counts correct */
122       free_locked_jcr(jcr);
123    }
124    unlock_jcr_chain();
125 }
126
127 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
128 {
129    bool cancel = false;
130
131    if (jcr->job->MaxWaitTime == 0) {
132       return false;
133    }
134    if ((watchdog_time - jcr->start_time) < jcr->job->MaxWaitTime) {
135       Dmsg3(200, "Job %p (%s) with MaxWaitTime %d not expired\n",
136             jcr, jcr->Job, jcr->job->MaxWaitTime);
137       return false;
138    }
139    Dmsg3(200, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
140          "checking status\n",
141          jcr->JobId, jcr->Job, jcr->job->MaxWaitTime);
142    switch (jcr->JobStatus) {
143       case JS_Created:
144       case JS_Blocked:
145       case JS_WaitFD:
146       case JS_WaitSD:
147       case JS_WaitStoreRes:
148       case JS_WaitClientRes:
149       case JS_WaitJobRes:
150       case JS_WaitPriority:
151       case JS_WaitMaxJobs:
152       case JS_WaitStartTime:
153          cancel = true;
154          Dmsg0(200, "JCR blocked in #1\n");
155          break;
156       case JS_Running:
157          Dmsg0(200, "JCR running, checking SD status\n");
158          switch (jcr->SDJobStatus) {
159             case JS_WaitMount:
160             case JS_WaitMedia:
161             case JS_WaitFD:
162                cancel = true;
163                Dmsg0(200, "JCR blocked in #2\n");
164                break;
165             default:
166                Dmsg0(200, "JCR not blocked in #2\n");
167                break;
168          }
169          break;
170       case JS_Terminated:
171       case JS_ErrorTerminated:
172       case JS_Canceled:
173          Dmsg0(200, "JCR already dead in #3\n");
174          break;
175       default:
176          Emsg1(M_ABORT, 0, _("Unhandled job status code %d\n"),
177                jcr->JobStatus);
178    }
179    Dmsg3(200, "MaxWaitTime result: %scancel JCR %p (%s)\n",
180          cancel ? "" : "do not ", jcr, jcr->job);
181
182    return cancel;
183 }
184
185 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
186 {
187    bool cancel = false;
188
189    if (jcr->job->MaxRunTime == 0) {
190       return false;
191    }
192    if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
193       Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
194             jcr, jcr->Job, jcr->job->MaxRunTime);
195       return false;
196    }
197
198    switch (jcr->JobStatus) {
199       case JS_Created:
200       case JS_Blocked:
201       case JS_WaitFD:
202       case JS_WaitSD:
203       case JS_WaitStoreRes:
204       case JS_WaitClientRes:
205       case JS_WaitJobRes:
206       case JS_WaitPriority:
207       case JS_WaitMaxJobs:
208       case JS_WaitStartTime:
209       case JS_Running:
210          cancel = true;
211          break;
212       case JS_Terminated:
213       case JS_ErrorTerminated:
214       case JS_Canceled:
215          cancel = false;
216          break;
217       default:
218          Emsg1(M_ABORT, 0, _("Unhandled job status code %d\n"),
219                jcr->JobStatus);
220    }
221
222    Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
223          cancel ? "" : "do not ", jcr, jcr->job);
224
225    return cancel;
226 }
227
228 /*
229  * Run a job -- typically called by the scheduler, but may also
230  *              be called by the UA (Console program).
231  *
232  */
233 void run_job(JCR *jcr)
234 {
235    int stat, errstat;
236
237    P(jcr->mutex);
238    sm_check(__FILE__, __LINE__, True);
239    init_msg(jcr, jcr->messages);
240    create_unique_job_name(jcr, jcr->job->hdr.name);
241    set_jcr_job_status(jcr, JS_Created);
242    jcr->jr.SchedTime = jcr->sched_time;
243    jcr->jr.StartTime = jcr->start_time;
244    jcr->jr.EndTime = 0;               /* perhaps rescheduled, clear it */
245    jcr->jr.Type = jcr->JobType;
246    jcr->jr.Level = jcr->JobLevel;
247    jcr->jr.JobStatus = jcr->JobStatus;
248    bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
249    bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
250
251    /* Initialize termination condition variable */
252    if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
253       Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat));
254       goto bail_out;
255    }
256
257    /*
258     * Open database
259     */
260    Dmsg0(50, "Open database\n");
261    jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
262                             jcr->catalog->db_password, jcr->catalog->db_address,
263                             jcr->catalog->db_port, jcr->catalog->db_socket);
264    if (!jcr->db || !db_open_database(jcr, jcr->db)) {
265       Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
266                  jcr->catalog->db_name);
267       if (jcr->db) {
268          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
269       }
270       goto bail_out;
271    }
272    Dmsg0(50, "DB opened\n");
273
274    /*
275     * Create Job record  
276     */
277    jcr->jr.JobStatus = jcr->JobStatus;
278    if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
279       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
280       goto bail_out;
281    }
282    jcr->JobId = jcr->jr.JobId;
283    ASSERT(jcr->jr.JobId > 0);
284
285    Dmsg4(50, "Created job record JobId=%d Name=%s Type=%c Level=%c\n", 
286        jcr->JobId, jcr->Job, jcr->jr.Type, jcr->jr.Level);
287    Dmsg0(200, "Add jrc to work queue\n");
288
289    /* Queue the job to be run */
290    if ((stat = jobq_add(&job_queue, jcr)) != 0) {
291       Emsg1(M_ABORT, 0, _("Could not add job queue: ERR=%s\n"), strerror(stat));
292    }
293    Dmsg0(100, "Done run_job()\n");
294
295    V(jcr->mutex);
296    return;
297
298 bail_out:
299    set_jcr_job_status(jcr, JS_ErrorTerminated);
300    V(jcr->mutex);
301    return;
302
303 }
304
305 /*
306  * Cancel a job -- typically called by the UA (Console program), but may also
307  *              be called by the job watchdog.
308  * 
309  *  Returns: 1 if cancel appears to be successful
310  *           0 on failure. Message sent to ua->jcr.
311  */
312 int cancel_job(UAContext *ua, JCR *jcr)
313 {
314    BSOCK *sd, *fd;
315
316    switch (jcr->JobStatus) {
317    case JS_Created:
318    case JS_WaitJobRes:
319    case JS_WaitClientRes:
320    case JS_WaitStoreRes:
321    case JS_WaitPriority:
322    case JS_WaitMaxJobs:
323    case JS_WaitStartTime:
324       set_jcr_job_status(jcr, JS_Canceled);
325       bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
326               jcr->JobId, jcr->Job);
327       jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
328       return 1;
329          
330    default:
331       set_jcr_job_status(jcr, JS_Canceled);
332
333       /* Cancel File daemon */
334       if (jcr->file_bsock) {
335          ua->jcr->client = jcr->client;
336          if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
337             bsendmsg(ua, _("Failed to connect to File daemon.\n"));
338             return 0;
339          }
340          Dmsg0(200, "Connected to file daemon\n");
341          fd = ua->jcr->file_bsock;
342          bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
343          while (bnet_recv(fd) >= 0) {
344             bsendmsg(ua, "%s", fd->msg);
345          }
346          bnet_sig(fd, BNET_TERMINATE);
347          bnet_close(fd);
348          ua->jcr->file_bsock = NULL;
349       }
350
351       /* Cancel Storage daemon */
352       if (jcr->store_bsock) {
353          ua->jcr->store = jcr->store;
354          if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
355             bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
356             return 0;
357          }
358          Dmsg0(200, "Connected to storage daemon\n");
359          sd = ua->jcr->store_bsock;
360          bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
361          while (bnet_recv(sd) >= 0) {
362             bsendmsg(ua, "%s", sd->msg);
363          }
364          bnet_sig(sd, BNET_TERMINATE);
365          bnet_close(sd);
366          ua->jcr->store_bsock = NULL;
367       }
368    }
369
370    return 1;
371 }
372
373 /* 
374  * This is the engine called by jobq.c:jobq_add() when we were pulled                
375  *  from the work queue.
376  *  At this point, we are running in our own thread and all
377  *    necessary resources are allocated -- see jobq.c
378  */
379 static void *job_thread(void *arg)
380 {
381    JCR *jcr = (JCR *)arg;
382
383    pthread_detach(pthread_self());
384    sm_check(__FILE__, __LINE__, True);
385
386    for ( ;; ) {
387
388       Dmsg0(200, "=====Start Job=========\n");
389       jcr->start_time = time(NULL);      /* set the real start time */
390       set_jcr_job_status(jcr, JS_Running);
391
392       if (job_canceled(jcr)) {
393          update_job_end_record(jcr);
394       } else if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
395           (utime_t)(jcr->start_time - jcr->sched_time)) {
396          Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
397          set_jcr_job_status(jcr, JS_Canceled);
398          update_job_end_record(jcr);
399       } else {
400
401          /* Run Job */
402          if (jcr->job->RunBeforeJob) {
403             POOLMEM *before = get_pool_memory(PM_FNAME);
404             int status;
405             BPIPE *bpipe;
406             char line[MAXSTRING];
407             
408             before = edit_job_codes(jcr, before, jcr->job->RunBeforeJob, "");
409             bpipe = open_bpipe(before, 0, "r");
410             free_pool_memory(before);
411             while (fgets(line, sizeof(line), bpipe->rfd)) {
412                Jmsg(jcr, M_INFO, 0, _("RunBefore: %s"), line);
413             }
414             status = close_bpipe(bpipe);
415             if (status != 0) {
416                Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob returned non-zero status=%d\n"),
417                   status);
418                set_jcr_job_status(jcr, JS_FatalError);
419                update_job_end_record(jcr);
420                goto bail_out;
421             }
422          }
423          switch (jcr->JobType) {
424          case JT_BACKUP:
425             do_backup(jcr);
426             if (jcr->JobStatus == JS_Terminated) {
427                do_autoprune(jcr);
428             }
429             break;
430          case JT_VERIFY:
431             do_verify(jcr);
432             if (jcr->JobStatus == JS_Terminated) {
433                do_autoprune(jcr);
434             }
435             break;
436          case JT_RESTORE:
437             do_restore(jcr);
438             if (jcr->JobStatus == JS_Terminated) {
439                do_autoprune(jcr);
440             }
441             break;
442          case JT_ADMIN:
443             do_admin(jcr);
444             if (jcr->JobStatus == JS_Terminated) {
445                do_autoprune(jcr);
446             }
447             break;
448          default:
449             Pmsg1(0, "Unimplemented job type: %d\n", jcr->JobType);
450             break;
451          }
452          if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
453              (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
454             POOLMEM *after = get_pool_memory(PM_FNAME);
455             int status;
456             BPIPE *bpipe;
457             char line[MAXSTRING];
458             
459             if (jcr->JobStatus == JS_Terminated) {
460                after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
461             } else {
462                after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
463             }
464             bpipe = open_bpipe(after, 0, "r");
465             free_pool_memory(after);
466             while (fgets(line, sizeof(line), bpipe->rfd)) {
467                Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
468             }
469             status = close_bpipe(bpipe);
470             if (status != 0) {
471                if (jcr->JobStatus == JS_Terminated) {
472                   Jmsg(jcr, M_FATAL, 0, _("RunAfterJob returned non-zero status=%d\n"),
473                        status);
474                } else {
475                   Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob returned non-zero status=%d\n"),
476                        status);
477                }
478                set_jcr_job_status(jcr, JS_FatalError);
479                update_job_end_record(jcr);
480             }
481          }
482       }
483 bail_out:
484       break;
485    }
486
487    Dmsg0(50, "======== End Job ==========\n");
488    sm_check(__FILE__, __LINE__, True);
489    return NULL;
490 }
491
492
493 /*
494  * Get or create a Client record for this Job
495  */
496 int get_or_create_client_record(JCR *jcr)
497 {
498    CLIENT_DBR cr;
499
500    memset(&cr, 0, sizeof(cr));
501    bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
502    cr.AutoPrune = jcr->client->AutoPrune;
503    cr.FileRetention = jcr->client->FileRetention;
504    cr.JobRetention = jcr->client->JobRetention;
505    if (!jcr->client_name) {
506       jcr->client_name = get_pool_memory(PM_NAME);
507    }
508    pm_strcpy(&jcr->client_name, jcr->client->hdr.name);
509    if (!db_create_client_record(jcr, jcr->db, &cr)) {
510       Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"), 
511          db_strerror(jcr->db));
512       return 0;
513    }
514    jcr->jr.ClientId = cr.ClientId;
515    if (cr.Uname[0]) {
516       if (!jcr->client_uname) {
517          jcr->client_uname = get_pool_memory(PM_NAME);
518       }
519       pm_strcpy(&jcr->client_uname, cr.Uname);
520    }
521    Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name, 
522       jcr->jr.ClientId);
523    return 1;
524 }
525
526
527 /*
528  * Write status and such in DB
529  */
530 void update_job_end_record(JCR *jcr)
531 {
532    if (jcr->jr.EndTime == 0) {
533       jcr->jr.EndTime = time(NULL);
534    }
535    jcr->end_time = jcr->jr.EndTime;
536    jcr->jr.JobId = jcr->JobId;
537    jcr->jr.JobStatus = jcr->JobStatus;
538    jcr->jr.JobFiles = jcr->JobFiles;
539    jcr->jr.JobBytes = jcr->JobBytes;
540    jcr->jr.VolSessionId = jcr->VolSessionId;
541    jcr->jr.VolSessionTime = jcr->VolSessionTime;
542    if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
543       Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"), 
544          db_strerror(jcr->db));
545    }
546 }
547
548 /*
549  * Takes base_name and appends (unique) current
550  *   date and time to form unique job name.
551  *
552  *  Returns: unique job name in jcr->Job
553  *    date/time in jcr->start_time
554  */
555 void create_unique_job_name(JCR *jcr, char *base_name)
556 {
557    /* Job start mutex */
558    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
559    static time_t last_start_time = 0;
560    time_t now;
561    struct tm tm;
562    char dt[MAX_TIME_LENGTH];
563    char name[MAX_NAME_LENGTH];
564    char *p;
565
566    /* Guarantee unique start time -- maximum one per second, and
567     * thus unique Job Name 
568     */
569    P(mutex);                          /* lock creation of jobs */
570    now = time(NULL);
571    while (now == last_start_time) {
572       bmicrosleep(0, 500000);
573       now = time(NULL);
574    }
575    last_start_time = now;
576    V(mutex);                          /* allow creation of jobs */
577    jcr->start_time = now;
578    /* Form Unique JobName */
579    localtime_r(&now, &tm);
580    /* Use only characters that are permitted in Windows filenames */
581    strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm); 
582    bstrncpy(name, base_name, sizeof(name));
583    name[sizeof(name)-22] = 0;          /* truncate if too long */
584    bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
585    /* Convert spaces into underscores */
586    for (p=jcr->Job; *p; p++) {
587       if (*p == ' ') {
588          *p = '_';
589       }
590    }
591 }
592
593 /*
594  * Free the Job Control Record if no one is still using it.
595  *  Called from main free_jcr() routine in src/lib/jcr.c so
596  *  that we can do our Director specific cleanup of the jcr.
597  */
598 void dird_free_jcr(JCR *jcr)
599 {
600    Dmsg0(200, "Start dird free_jcr\n");
601
602    if (jcr->sd_auth_key) {
603       free(jcr->sd_auth_key);
604       jcr->sd_auth_key = NULL;
605    }
606    if (jcr->where) {
607       free(jcr->where);
608       jcr->where = NULL;
609    }
610    if (jcr->file_bsock) {
611       Dmsg0(200, "Close File bsock\n");
612       bnet_close(jcr->file_bsock);
613       jcr->file_bsock = NULL;
614    }
615    if (jcr->store_bsock) {
616       Dmsg0(200, "Close Store bsock\n");
617       bnet_close(jcr->store_bsock);
618       jcr->store_bsock = NULL;
619    }
620    if (jcr->fname) {  
621       Dmsg0(200, "Free JCR fname\n");
622       free_pool_memory(jcr->fname);
623       jcr->fname = NULL;
624    }
625    if (jcr->stime) {
626       Dmsg0(200, "Free JCR stime\n");
627       free_pool_memory(jcr->stime);
628       jcr->stime = NULL;
629    }
630    if (jcr->RestoreBootstrap) {
631       free(jcr->RestoreBootstrap);
632       jcr->RestoreBootstrap = NULL;
633    }
634    if (jcr->client_uname) {
635       free_pool_memory(jcr->client_uname);
636       jcr->client_uname = NULL;
637    }
638    pthread_cond_destroy(&jcr->term_wait);
639    Dmsg0(200, "End dird free_jcr\n");
640 }
641
642 /*
643  * Set some defaults in the JCR necessary to
644  * run. These items are pulled from the job
645  * definition as defaults, but can be overridden
646  * later either by the Run record in the Schedule resource,
647  * or by the Console program.
648  */
649 void set_jcr_defaults(JCR *jcr, JOB *job)
650 {
651    jcr->job = job;
652    jcr->JobType = job->JobType;
653    switch (jcr->JobType) {
654    case JT_ADMIN:
655    case JT_RESTORE:
656       jcr->JobLevel = L_NONE;
657       break;
658    default:
659       jcr->JobLevel = job->level;
660       break;
661    }
662    jcr->JobPriority = job->Priority;
663    jcr->store = job->storage;
664    jcr->client = job->client;
665    if (!jcr->client_name) {
666       jcr->client_name = get_pool_memory(PM_NAME);
667    }
668    pm_strcpy(&jcr->client_name, jcr->client->hdr.name);
669    jcr->pool = job->pool;
670    jcr->catalog = job->client->catalog;
671    jcr->fileset = job->fileset;
672    jcr->messages = job->messages; 
673    if (jcr->RestoreBootstrap) {
674       free(jcr->RestoreBootstrap);
675       jcr->RestoreBootstrap = NULL;
676    }
677    /* This can be overridden by Console program */
678    if (job->RestoreBootstrap) {
679       jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
680    }
681    /* If no default level given, set one */
682    if (jcr->JobLevel == 0) {
683       switch (jcr->JobType) {
684       case JT_VERIFY:
685          jcr->JobLevel = L_VERIFY_CATALOG;
686          break;
687       case JT_BACKUP:
688          jcr->JobLevel = L_INCREMENTAL;
689          break;
690       case JT_RESTORE:
691       case JT_ADMIN:
692          jcr->JobLevel = L_NONE;
693          break;
694       default:
695          break;
696       }
697    }
698 }