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