]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/job.c
Misc -- see kes-1.32
[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 int acquire_resource_locks(JCR *jcr);
35 #ifdef USE_SEMAPHORE
36 static void backoff_resource_locks(JCR *jcr, int count);
37 static void release_resource_locks(JCR *jcr);
38 #endif
39
40 /* Exported subroutines */
41
42
43 /* Imported subroutines */
44 extern void term_scheduler();
45 extern void term_ua_server();
46 extern int do_backup(JCR *jcr);
47 extern int do_admin(JCR *jcr);
48 extern int do_restore(JCR *jcr);
49 extern int do_verify(JCR *jcr);
50
51 #ifdef USE_SEMAPHORE
52 static semlock_t job_lock;
53 static pthread_mutex_t mutex;
54 static pthread_cond_t  resource_wait;
55 static int waiting = 0;               /* count of waiting threads */
56 #else
57 #ifdef JOB_QUEUE  
58 jobq_t  job_queue;
59 #endif
60 #endif
61
62 void init_job_server(int max_workers)
63 {
64    int stat;
65 #ifdef USE_SEMAPHORE
66    if ((stat = sem_init(&job_lock, max_workers)) != 0) {
67       Emsg1(M_ABORT, 0, _("Could not init job lock: ERR=%s\n"), strerror(stat));
68    }
69    if ((stat = pthread_mutex_init(&mutex, NULL)) != 0) {
70       Emsg1(M_ABORT, 0, _("Could not init resource mutex: ERR=%s\n"), strerror(stat));
71    }
72    if ((stat = pthread_cond_init(&resource_wait, NULL)) != 0) {
73       Emsg1(M_ABORT, 0, _("Could not init resource wait: ERR=%s\n"), strerror(stat));
74    }
75
76 #else
77 #ifdef JOB_QUEUE
78    if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
79       Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), strerror(stat));
80    }
81 #endif
82 #endif
83    return;
84 }
85
86 /*
87  * Run a job -- typically called by the scheduler, but may also
88  *              be called by the UA (Console program).
89  *
90  */
91 void run_job(JCR *jcr)
92 {
93    int stat, errstat;
94 #ifdef USE_SEMAPHORE
95    pthread_t tid;
96 #endif
97
98    sm_check(__FILE__, __LINE__, True);
99    init_msg(jcr, jcr->messages);
100    create_unique_job_name(jcr, jcr->job->hdr.name);
101    set_jcr_job_status(jcr, JS_Created);
102    jcr->jr.SchedTime = jcr->sched_time;
103    jcr->jr.StartTime = jcr->start_time;
104    jcr->jr.Type = jcr->JobType;
105    jcr->jr.Level = jcr->JobLevel;
106    jcr->jr.JobStatus = jcr->JobStatus;
107    bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
108    bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
109
110    /* Initialize termination condition variable */
111    if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
112       Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat));
113       set_jcr_job_status(jcr, JS_ErrorTerminated);
114       free_jcr(jcr);
115       return;
116    }
117
118    /*
119     * Open database
120     */
121    Dmsg0(50, "Open database\n");
122    jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
123                             jcr->catalog->db_password, jcr->catalog->db_address,
124                             jcr->catalog->db_port, jcr->catalog->db_socket);
125    if (!db_open_database(jcr, jcr->db)) {
126       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
127       set_jcr_job_status(jcr, JS_ErrorTerminated);
128       free_jcr(jcr);
129       return;
130    }
131    Dmsg0(50, "DB opened\n");
132
133    /*
134     * Create Job record  
135     */
136    jcr->jr.JobStatus = jcr->JobStatus;
137    if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
138       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
139       set_jcr_job_status(jcr, JS_ErrorTerminated);
140       free_jcr(jcr);
141       return;
142    }
143    jcr->JobId = jcr->jr.JobId;
144    ASSERT(jcr->jr.JobId > 0);
145
146    Dmsg4(50, "Created job record JobId=%d Name=%s Type=%c Level=%c\n", 
147        jcr->JobId, jcr->Job, jcr->jr.Type, jcr->jr.Level);
148    Dmsg0(200, "Add jrc to work queue\n");
149
150 #ifdef USE_SEMAPHORE
151   if ((stat = pthread_create(&tid, NULL, job_thread, (void *)jcr)) != 0) {
152       Emsg1(M_ABORT, 0, _("Unable to create job thread: ERR=%s\n"), strerror(stat));
153    }
154 #else
155 #ifdef JOB_QUEUE
156    /* Queue the job to be run */
157    if ((stat = jobq_add(&job_queue, jcr)) != 0) {
158       Emsg1(M_ABORT, 0, _("Could not add job queue: ERR=%s\n"), strerror(stat));
159    }
160 #endif
161 #endif
162    Dmsg0(100, "Done run_job()\n");
163 }
164
165 /* 
166  * This is the engine called by workq_add() when we were pulled                
167  *  from the work queue.
168  *  At this point, we are running in our own thread 
169  */
170 static void *job_thread(void *arg)
171 {
172    JCR *jcr = (JCR *)arg;
173
174    pthread_detach(pthread_self());
175    sm_check(__FILE__, __LINE__, True);
176
177    for ( ;; ) {
178       if (!acquire_resource_locks(jcr)) {
179          set_jcr_job_status(jcr, JS_Canceled);
180       }
181
182       Dmsg0(200, "=====Start Job=========\n");
183       jcr->start_time = time(NULL);      /* set the real start time */
184       set_jcr_job_status(jcr, JS_Running);
185
186       if (job_canceled(jcr)) {
187          update_job_end_record(jcr);
188       } else if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
189           (utime_t)(jcr->start_time - jcr->sched_time)) {
190          Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
191          set_jcr_job_status(jcr, JS_Canceled);
192          update_job_end_record(jcr);
193       } else {
194
195          /* Run Job */
196          if (jcr->job->RunBeforeJob) {
197             POOLMEM *before = get_pool_memory(PM_FNAME);
198             int status;
199             BPIPE *bpipe;
200             char line[MAXSTRING];
201             
202             before = edit_job_codes(jcr, before, jcr->job->RunBeforeJob, "");
203             bpipe = open_bpipe(before, 0, "r");
204             free_pool_memory(before);
205             while (fgets(line, sizeof(line), bpipe->rfd)) {
206                Jmsg(jcr, M_INFO, 0, _("RunBefore: %s"), line);
207             }
208             status = close_bpipe(bpipe);
209             if (status != 0) {
210                Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob returned non-zero status=%d\n"),
211                   status);
212                set_jcr_job_status(jcr, JS_FatalError);
213                update_job_end_record(jcr);
214                goto bail_out;
215             }
216          }
217          switch (jcr->JobType) {
218          case JT_BACKUP:
219             do_backup(jcr);
220             if (jcr->JobStatus == JS_Terminated) {
221                do_autoprune(jcr);
222             }
223             break;
224          case JT_VERIFY:
225             do_verify(jcr);
226             if (jcr->JobStatus == JS_Terminated) {
227                do_autoprune(jcr);
228             }
229             break;
230          case JT_RESTORE:
231             do_restore(jcr);
232             if (jcr->JobStatus == JS_Terminated) {
233                do_autoprune(jcr);
234             }
235             break;
236          case JT_ADMIN:
237             do_admin(jcr);
238             if (jcr->JobStatus == JS_Terminated) {
239                do_autoprune(jcr);
240             }
241             break;
242          default:
243             Pmsg1(0, "Unimplemented job type: %d\n", jcr->JobType);
244             break;
245          }
246          if (jcr->job->RunAfterJob) {
247             POOLMEM *after = get_pool_memory(PM_FNAME);
248             int status;
249             BPIPE *bpipe;
250             char line[MAXSTRING];
251             
252             after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
253             bpipe = open_bpipe(after, 0, "r");
254             free_pool_memory(after);
255             while (fgets(line, sizeof(line), bpipe->rfd)) {
256                Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
257             }
258             status = close_bpipe(bpipe);
259             if (status != 0) {
260                Jmsg(jcr, M_FATAL, 0, _("RunAfterJob returned non-zero status=%d\n"),
261                   status);
262                set_jcr_job_status(jcr, JS_FatalError);
263                update_job_end_record(jcr);
264             }
265          }
266       }
267 bail_out:
268 #ifndef JOB_QUEUE
269       release_resource_locks(jcr);
270       if (jcr->job->RescheduleOnError && 
271           jcr->JobStatus != JS_Terminated &&
272           jcr->JobStatus != JS_Canceled && 
273           jcr->job->RescheduleTimes > 0 && 
274           jcr->reschedule_count < jcr->job->RescheduleTimes) {
275
276           /*
277            * Reschedule this job by cleaning it up, but
278            *  reuse the same JobId if possible.
279            */
280          jcr->reschedule_count++;
281          jcr->sched_time = time(NULL) + jcr->job->RescheduleInterval;
282          Dmsg2(100, "Rescheduled Job %s to re-run in %d seconds.\n", jcr->Job,
283             (int)jcr->job->RescheduleInterval);
284          jcr->JobStatus = JS_Created; /* force new status */
285          dird_free_jcr(jcr);          /* partial cleanup old stuff */
286          if (jcr->JobBytes == 0) {
287             continue;                    /* reschedule the job */
288          }
289          /* 
290           * Something was actually backed up, so we cannot reuse
291           *   the old JobId or there will be database record
292           *   conflicts.  We now create a new job, copying the
293           *   appropriate fields.
294           */
295          JCR *njcr = new_jcr(sizeof(JCR), dird_free_jcr);
296          set_jcr_defaults(njcr, jcr->job);
297          njcr->reschedule_count = jcr->reschedule_count;
298          njcr->JobLevel = jcr->JobLevel;
299          njcr->JobStatus = jcr->JobStatus;
300          njcr->pool = jcr->pool;
301          njcr->store = jcr->store;
302          njcr->messages = jcr->messages;
303          run_job(njcr);
304       }
305 #endif
306       break;
307    }
308
309 #ifndef JOB_QUEUE
310    if (jcr->db) {
311       Dmsg0(200, "Close DB\n");
312       db_close_database(jcr, jcr->db);
313       jcr->db = NULL;
314    }
315    free_jcr(jcr);
316 #endif
317    Dmsg0(50, "======== End Job ==========\n");
318    sm_check(__FILE__, __LINE__, True);
319    return NULL;
320 }
321
322 /*
323  * Acquire the resources needed. These locks limit the
324  *  number of jobs by each resource. We have limits on
325  *  Jobs, Clients, Storage, and total jobs.
326  */
327 static int acquire_resource_locks(JCR *jcr)
328 {
329 #ifndef JOB_QUEUE
330    time_t now = time(NULL);
331    time_t wtime = jcr->sched_time - now;
332
333    /* Wait until scheduled time arrives */
334    if (wtime > 0 && verbose) {
335       Jmsg(jcr, M_INFO, 0, _("Job %s waiting %d seconds for scheduled start time.\n"), 
336          jcr->Job, wtime);
337       set_jcr_job_status(jcr, JS_WaitStartTime);
338    }
339    /* Check every 30 seconds if canceled */ 
340    while (wtime > 0) {
341       Dmsg2(100, "Waiting on sched time, jobid=%d secs=%d\n", jcr->JobId, wtime);
342       if (wtime > 30) {
343          wtime = 30;
344       }
345       bmicrosleep(wtime, 0);
346       if (job_canceled(jcr)) {
347          return 0;
348       }
349       wtime = jcr->sched_time - time(NULL);
350    }
351 #endif
352
353
354 #ifdef USE_SEMAPHORE
355    int stat;
356
357    /* Initialize semaphores */
358    if (jcr->store->sem.valid != SEMLOCK_VALID) {
359       if ((stat = sem_init(&jcr->store->sem, jcr->store->MaxConcurrentJobs)) != 0) {
360          Emsg1(M_ABORT, 0, _("Could not init Storage semaphore: ERR=%s\n"), strerror(stat));
361       }
362    }
363    if (jcr->client->sem.valid != SEMLOCK_VALID) {
364       if ((stat = sem_init(&jcr->client->sem, jcr->client->MaxConcurrentJobs)) != 0) {
365          Emsg1(M_ABORT, 0, _("Could not init Client semaphore: ERR=%s\n"), strerror(stat));
366       }
367    }
368    if (jcr->job->sem.valid != SEMLOCK_VALID) {
369       if ((stat = sem_init(&jcr->job->sem, jcr->job->MaxConcurrentJobs)) != 0) {
370          Emsg1(M_ABORT, 0, _("Could not init Job semaphore: ERR=%s\n"), strerror(stat));
371       }
372    }
373
374    for ( ;; ) {
375       /* Acquire semaphore */
376       set_jcr_job_status(jcr, JS_WaitJobRes);
377       if ((stat = sem_lock(&jcr->job->sem)) != 0) {
378          Emsg1(M_ABORT, 0, _("Could not acquire Job max jobs lock: ERR=%s\n"), strerror(stat));
379       }
380       set_jcr_job_status(jcr, JS_WaitClientRes);
381       if ((stat = sem_trylock(&jcr->client->sem)) != 0) {
382          if (stat == EBUSY) {
383             backoff_resource_locks(jcr, 1);
384             goto wait;
385          } else {
386             Emsg1(M_ABORT, 0, _("Could not acquire Client max jobs lock: ERR=%s\n"), strerror(stat));
387          }
388       }
389       set_jcr_job_status(jcr, JS_WaitStoreRes);
390       if ((stat = sem_trylock(&jcr->store->sem)) != 0) {
391          if (stat == EBUSY) {
392             backoff_resource_locks(jcr, 2);
393             goto wait;
394          } else {
395             Emsg1(M_ABORT, 0, _("Could not acquire Storage max jobs lock: ERR=%s\n"), strerror(stat));
396          }
397       }
398       set_jcr_job_status(jcr, JS_WaitMaxJobs);
399       if ((stat = sem_trylock(&job_lock)) != 0) {
400          if (stat == EBUSY) {
401             backoff_resource_locks(jcr, 3);
402             goto wait;
403          } else {
404             Emsg1(M_ABORT, 0, _("Could not acquire max jobs lock: ERR=%s\n"), strerror(stat));
405          }
406       }
407       break;
408
409 wait:
410       if (job_canceled(jcr)) {
411          return 0;
412       }
413       P(mutex);
414       /*
415        * Wait for a resource to be released either by backoff or
416        *  by a job terminating.
417        */
418       waiting++;
419       pthread_cond_wait(&resource_wait, &mutex);
420       waiting--;
421       V(mutex);
422       /* Try again */
423    }
424    jcr->acquired_resource_locks = true;
425 #endif
426    return 1;
427 }
428
429 #ifdef USE_SEMAPHORE
430 /*
431  * We could not get all the resource locks because 
432  *  too many jobs are running, so release any locks
433  *  we did acquire, giving others a chance to use them
434  *  while we wait.
435  */
436 static void backoff_resource_locks(JCR *jcr, int count)
437 {
438    P(mutex);
439    switch (count) {
440    case 3:
441       sem_unlock(&jcr->store->sem);
442       /* Fall through wanted */
443    case 2:
444       sem_unlock(&jcr->client->sem);
445       /* Fall through wanted */
446    case 1:
447       sem_unlock(&jcr->job->sem);
448       break;
449    }
450    /*
451     * Since we released a lock, if there are any threads
452     *  waiting, wake them up so that they can try again.
453     */
454    if (waiting > 0) {
455       pthread_cond_broadcast(&resource_wait);
456    }
457    V(mutex);
458 }
459 #endif
460
461 /*
462  * This is called at the end of the job to release
463  *   any resource limits on the number of jobs. If
464  *   there are any other jobs waiting, we wake them
465  *   up so that they can try again.
466  */
467 #ifdef USE_SEMAPHORE
468 static void release_resource_locks(JCR *jcr)
469 {
470    if (!jcr->acquired_resource_locks) {
471       return;                         /* Job canceled, no locks acquired */
472    }
473    P(mutex);
474    sem_unlock(&jcr->store->sem);
475    sem_unlock(&jcr->client->sem);
476    sem_unlock(&jcr->job->sem);
477    sem_unlock(&job_lock);
478    if (waiting > 0) {
479       pthread_cond_broadcast(&resource_wait);
480    }
481    jcr->acquired_resource_locks = false;
482    V(mutex);
483 }
484 #endif
485
486 /*
487  * Get or create a Client record for this Job
488  */
489 int get_or_create_client_record(JCR *jcr)
490 {
491    CLIENT_DBR cr;
492
493    memset(&cr, 0, sizeof(cr));
494    bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
495    cr.AutoPrune = jcr->client->AutoPrune;
496    cr.FileRetention = jcr->client->FileRetention;
497    cr.JobRetention = jcr->client->JobRetention;
498    if (!jcr->client_name) {
499       jcr->client_name = get_pool_memory(PM_NAME);
500    }
501    pm_strcpy(&jcr->client_name, jcr->client->hdr.name);
502    if (!db_create_client_record(jcr, jcr->db, &cr)) {
503       Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"), 
504          db_strerror(jcr->db));
505       return 0;
506    }
507    jcr->jr.ClientId = cr.ClientId;
508    if (cr.Uname[0]) {
509       if (!jcr->client_uname) {
510          jcr->client_uname = get_pool_memory(PM_NAME);
511       }
512       pm_strcpy(&jcr->client_uname, cr.Uname);
513    }
514    Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name, 
515       jcr->jr.ClientId);
516    return 1;
517 }
518
519
520 /*
521  * Write status and such in DB
522  */
523 void update_job_end_record(JCR *jcr)
524 {
525    if (jcr->jr.EndTime == 0) {
526       jcr->jr.EndTime = time(NULL);
527    }
528    jcr->end_time = jcr->jr.EndTime;
529    jcr->jr.JobId = jcr->JobId;
530    jcr->jr.JobStatus = jcr->JobStatus;
531    jcr->jr.JobFiles = jcr->JobFiles;
532    jcr->jr.JobBytes = jcr->JobBytes;
533    jcr->jr.VolSessionId = jcr->VolSessionId;
534    jcr->jr.VolSessionTime = jcr->VolSessionTime;
535    if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
536       Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"), 
537          db_strerror(jcr->db));
538    }
539 }
540
541 /*
542  * Takes base_name and appends (unique) current
543  *   date and time to form unique job name.
544  *
545  *  Returns: unique job name in jcr->Job
546  *    date/time in jcr->start_time
547  */
548 void create_unique_job_name(JCR *jcr, char *base_name)
549 {
550    /* Job start mutex */
551    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
552    static time_t last_start_time = 0;
553    time_t now;
554    struct tm tm;
555    char dt[MAX_TIME_LENGTH];
556    char name[MAX_NAME_LENGTH];
557    char *p;
558
559    /* Guarantee unique start time -- maximum one per second, and
560     * thus unique Job Name 
561     */
562    P(mutex);                          /* lock creation of jobs */
563    now = time(NULL);
564    while (now == last_start_time) {
565       bmicrosleep(0, 500000);
566       now = time(NULL);
567    }
568    last_start_time = now;
569    V(mutex);                          /* allow creation of jobs */
570    jcr->start_time = now;
571    /* Form Unique JobName */
572    localtime_r(&now, &tm);
573    /* Use only characters that are permitted in Windows filenames */
574    strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm); 
575    bstrncpy(name, base_name, sizeof(name));
576    name[sizeof(name)-22] = 0;          /* truncate if too long */
577    bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
578    /* Convert spaces into underscores */
579    for (p=jcr->Job; *p; p++) {
580       if (*p == ' ') {
581          *p = '_';
582       }
583    }
584 }
585
586 /*
587  * Free the Job Control Record if no one is still using it.
588  *  Called from main free_jcr() routine in src/lib/jcr.c so
589  *  that we can do our Director specific cleanup of the jcr.
590  */
591 void dird_free_jcr(JCR *jcr)
592 {
593    Dmsg0(200, "Start dird free_jcr\n");
594
595    if (jcr->sd_auth_key) {
596       free(jcr->sd_auth_key);
597       jcr->sd_auth_key = NULL;
598    }
599    if (jcr->where) {
600       free(jcr->where);
601       jcr->where = NULL;
602    }
603    if (jcr->file_bsock) {
604       Dmsg0(200, "Close File bsock\n");
605       bnet_close(jcr->file_bsock);
606       jcr->file_bsock = NULL;
607    }
608    if (jcr->store_bsock) {
609       Dmsg0(200, "Close Store bsock\n");
610       bnet_close(jcr->store_bsock);
611       jcr->store_bsock = NULL;
612    }
613    if (jcr->fname) {  
614       Dmsg0(200, "Free JCR fname\n");
615       free_pool_memory(jcr->fname);
616       jcr->fname = NULL;
617    }
618    if (jcr->stime) {
619       Dmsg0(200, "Free JCR stime\n");
620       free_pool_memory(jcr->stime);
621       jcr->stime = NULL;
622    }
623    if (jcr->RestoreBootstrap) {
624       free(jcr->RestoreBootstrap);
625       jcr->RestoreBootstrap = NULL;
626    }
627    if (jcr->client_uname) {
628       free_pool_memory(jcr->client_uname);
629       jcr->client_uname = NULL;
630    }
631    Dmsg0(200, "End dird free_jcr\n");
632 }
633
634 /*
635  * Set some defaults in the JCR necessary to
636  * run. These items are pulled from the job
637  * definition as defaults, but can be overridden
638  * later either by the Run record in the Schedule resource,
639  * or by the Console program.
640  */
641 void set_jcr_defaults(JCR *jcr, JOB *job)
642 {
643    jcr->job = job;
644    jcr->JobType = job->JobType;
645    jcr->JobLevel = job->level;
646    jcr->JobPriority = job->Priority;
647    jcr->store = job->storage;
648    jcr->client = job->client;
649    if (!jcr->client_name) {
650       jcr->client_name = get_pool_memory(PM_NAME);
651    }
652    pm_strcpy(&jcr->client_name, jcr->client->hdr.name);
653    jcr->pool = job->pool;
654    jcr->catalog = job->client->catalog;
655    jcr->fileset = job->fileset;
656    jcr->messages = job->messages; 
657    if (jcr->RestoreBootstrap) {
658       free(jcr->RestoreBootstrap);
659    }
660    /* This can be overridden by Console program */
661    if (job->RestoreBootstrap) {
662       jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
663    }
664    /* If no default level given, set one */
665    if (jcr->JobLevel == 0) {
666       switch (jcr->JobType) {
667       case JT_VERIFY:
668          jcr->JobLevel = L_VERIFY_CATALOG;
669          break;
670       case JT_BACKUP:
671          jcr->JobLevel = L_INCREMENTAL;
672          break;
673       case JT_RESTORE:
674       case JT_ADMIN:
675          jcr->JobLevel = L_FULL;
676          break;
677       default:
678          break;
679       }
680    }
681 }