]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/job.c
migrate
[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-2006 Kern Sibbald
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
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
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 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26
27 /* Forward referenced subroutines */
28 static void *job_thread(void *arg);
29 static void job_monitor_watchdog(watchdog_t *self);
30 static void job_monitor_destructor(watchdog_t *self);
31 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr);
32 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr);
33
34 /* Imported subroutines */
35 extern void term_scheduler();
36 extern void term_ua_server();
37
38 /* Imported variables */
39 extern time_t watchdog_time;
40
41 jobq_t job_queue;
42
43 void init_job_server(int max_workers)
44 {
45    int stat;
46    watchdog_t *wd;
47
48    if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
49       berrno be;
50       Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.strerror(stat));
51    }
52    wd = new_watchdog();
53    wd->callback = job_monitor_watchdog;
54    wd->destructor = job_monitor_destructor;
55    wd->one_shot = false;
56    wd->interval = 60;
57    wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
58    register_watchdog(wd);
59 }
60
61 void term_job_server()
62 {
63    jobq_destroy(&job_queue);          /* ignore any errors */
64 }
65
66 /*
67  * Run a job -- typically called by the scheduler, but may also
68  *              be called by the UA (Console program).
69  *
70  *  Returns: 0 on failure
71  *           JobId on success
72  *
73  */
74 JobId_t run_job(JCR *jcr)
75 {
76    int stat;
77    if (setup_job(jcr)) {
78       /* Queue the job to be run */
79       if ((stat = jobq_add(&job_queue, jcr)) != 0) {
80          berrno be;
81          Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.strerror(stat));
82          return 0;
83       }
84       return jcr->JobId;
85    }
86    return 0;
87 }            
88
89 bool setup_job(JCR *jcr) 
90 {
91    int errstat;
92
93    jcr->lock();
94    sm_check(__FILE__, __LINE__, true);
95    init_msg(jcr, jcr->messages);
96
97    /* Initialize termination condition variable */
98    if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
99       berrno be;
100       Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.strerror(errstat));
101       goto bail_out;
102    }
103    jcr->term_wait_inited = true;
104
105    create_unique_job_name(jcr, jcr->job->hdr.name);
106    set_jcr_job_status(jcr, JS_Created);
107    jcr->unlock();
108
109    /*
110     * Open database
111     */
112    Dmsg0(50, "Open database\n");
113    jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
114                             jcr->catalog->db_password, jcr->catalog->db_address,
115                             jcr->catalog->db_port, jcr->catalog->db_socket,
116                             jcr->catalog->mult_db_connections);
117    if (!jcr->db || !db_open_database(jcr, jcr->db)) {
118       Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
119                  jcr->catalog->db_name);
120       if (jcr->db) {
121          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
122       }
123       goto bail_out;
124    }
125    Dmsg0(50, "DB opened\n");
126
127    /*
128     * Create Job record
129     */
130    init_jcr_job_record(jcr);
131    if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
132       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
133       goto bail_out;
134    }
135    jcr->JobId = jcr->jr.JobId;
136    Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
137        jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
138
139    generate_daemon_event(jcr, "JobStart");
140
141    if (!get_or_create_client_record(jcr)) {
142       goto bail_out;
143    }
144
145    if (job_canceled(jcr)) {
146       goto bail_out;
147    }
148
149    Dmsg0(200, "Add jrc to work queue\n");
150
151
152    return true;
153
154 bail_out:
155    if (jcr->fname) {
156       free_memory(jcr->fname);
157       jcr->fname = NULL;
158    }
159    return false;
160 }
161
162
163 /*
164  * This is the engine called by jobq.c:jobq_add() when we were pulled
165  *  from the work queue.
166  *  At this point, we are running in our own thread and all
167  *    necessary resources are allocated -- see jobq.c
168  */
169 static void *job_thread(void *arg)
170 {
171    JCR *jcr = (JCR *)arg;
172
173    jcr->my_thread_id = pthread_self();
174    pthread_detach(jcr->my_thread_id);
175    sm_check(__FILE__, __LINE__, true);
176
177    Dmsg0(200, "=====Start Job=========\n");
178    jcr->start_time = time(NULL);      /* set the real start time */
179    jcr->jr.StartTime = jcr->start_time;
180
181    if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
182        (utime_t)(jcr->start_time - jcr->sched_time)) {
183       Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
184       set_jcr_job_status(jcr, JS_Canceled);
185    }
186
187    /*                                
188     * Note, we continue, even if the job is canceled above. This
189     *  will permit proper setting of the job start record and
190     *  the error (cancel) will be picked up below.
191     */
192
193    generate_job_event(jcr, "JobInit");
194    set_jcr_job_status(jcr, JS_Running);   /* this will be set only if no error */
195
196    if (!jcr->fname) {
197       jcr->fname = get_pool_memory(PM_FNAME);
198    }
199
200    /*
201     * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
202     *  this allows us to setup a proper job start record for restarting
203     *  in case of later errors.
204     */
205    switch (jcr->JobType) {
206    case JT_BACKUP:
207       if (!do_backup_init(jcr)) {
208          backup_cleanup(jcr, JS_ErrorTerminated);
209       }
210       break;
211    case JT_VERIFY:
212       if (!do_verify_init(jcr)) {
213          verify_cleanup(jcr, JS_ErrorTerminated);
214       }
215       break;
216    case JT_RESTORE:
217       if (!do_restore_init(jcr)) {
218          restore_cleanup(jcr, JS_ErrorTerminated);
219       }
220       break;
221    case JT_ADMIN:
222       if (!do_admin_init(jcr)) {
223          admin_cleanup(jcr, JS_ErrorTerminated);
224       }
225       break;
226    case JT_MIGRATE:
227       if (!do_migration_init(jcr)) { 
228          migration_cleanup(jcr, JS_ErrorTerminated);
229       }
230       break;
231    default:
232       Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
233       set_jcr_job_status(jcr, JS_ErrorTerminated);
234       break;
235    }
236
237    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
238       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
239    }
240
241    if (job_canceled(jcr)) {
242       update_job_end_record(jcr);
243
244    } else {
245
246       /* Run Job */
247       if (jcr->job->RunBeforeJob) {
248          POOLMEM *before = get_pool_memory(PM_FNAME);
249          int status;
250          BPIPE *bpipe;
251          char line[MAXSTRING];
252
253          before = edit_job_codes(jcr, before, jcr->job->RunBeforeJob, "");
254          bpipe = open_bpipe(before, 0, "r");
255          free_pool_memory(before);
256          while (fgets(line, sizeof(line), bpipe->rfd)) {
257             Jmsg(jcr, M_INFO, 0, _("RunBefore: %s"), line);
258          }
259          status = close_bpipe(bpipe);
260          if (status != 0) {
261             berrno be;
262             Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob error: ERR=%s\n"), be.strerror(status));
263             set_jcr_job_status(jcr, JS_FatalError);
264             update_job_end_record(jcr);
265             goto bail_out;
266          }
267       }
268
269       generate_job_event(jcr, "JobRun");
270
271       switch (jcr->JobType) {
272       case JT_BACKUP:
273          if (do_backup(jcr)) {
274             do_autoprune(jcr);
275          } else {
276             backup_cleanup(jcr, JS_ErrorTerminated);
277          }
278          break;
279       case JT_VERIFY:
280          if (do_verify(jcr)) {
281             do_autoprune(jcr);
282          } else {
283             verify_cleanup(jcr, JS_ErrorTerminated);
284          }
285          break;
286       case JT_RESTORE:
287          if (do_restore(jcr)) {
288             do_autoprune(jcr);
289          } else {
290             restore_cleanup(jcr, JS_ErrorTerminated);
291          }
292          break;
293       case JT_ADMIN:
294          if (do_admin(jcr)) {
295             do_autoprune(jcr);
296          } else {
297             admin_cleanup(jcr, JS_ErrorTerminated);
298          }
299          break;
300       case JT_MIGRATE:
301       case JT_COPY:
302       case JT_ARCHIVE:
303          if (do_migration(jcr)) {
304             do_autoprune(jcr);
305          } else {
306             migration_cleanup(jcr, JS_ErrorTerminated);
307          }
308          break;
309       default:
310          Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
311          break;
312       }
313       if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
314           (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
315          POOLMEM *after = get_pool_memory(PM_FNAME);
316          int status;
317          BPIPE *bpipe;
318          char line[MAXSTRING];
319
320          if (jcr->JobStatus == JS_Terminated) {
321             after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
322          } else {
323             after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
324          }
325          bpipe = open_bpipe(after, 0, "r");
326          free_pool_memory(after);
327          while (fgets(line, sizeof(line), bpipe->rfd)) {
328             Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
329          }
330          status = close_bpipe(bpipe);
331          /*
332           * Note, if we get an error here, do not mark the
333           *  job in error, simply report the error condition.
334           */
335          if (status != 0) {
336             berrno be;
337             if (jcr->JobStatus == JS_Terminated) {
338                Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror(status));
339             } else {
340                Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror(status));
341             }
342          }
343       }
344       /* Send off any queued messages */
345       if (jcr->msg_queue->size() > 0) {
346          dequeue_messages(jcr);
347       }
348    }
349
350 bail_out:
351    generate_daemon_event(jcr, "JobEnd");
352    Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
353    sm_check(__FILE__, __LINE__, true);
354    return NULL;
355 }
356
357
358 /*
359  * Cancel a job -- typically called by the UA (Console program), but may also
360  *              be called by the job watchdog.
361  *
362  *  Returns: true  if cancel appears to be successful
363  *           false on failure. Message sent to ua->jcr.
364  */
365 bool cancel_job(UAContext *ua, JCR *jcr)
366 {
367    BSOCK *sd, *fd;
368
369    set_jcr_job_status(jcr, JS_Canceled);
370
371    switch (jcr->JobStatus) {
372    case JS_Created:
373    case JS_WaitJobRes:
374    case JS_WaitClientRes:
375    case JS_WaitStoreRes:
376    case JS_WaitPriority:
377    case JS_WaitMaxJobs:
378    case JS_WaitStartTime:
379       bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
380               jcr->JobId, jcr->Job);
381       jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
382       return true;
383
384    default:
385       /* Cancel File daemon */
386       if (jcr->file_bsock) {
387          ua->jcr->client = jcr->client;
388          if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
389             bsendmsg(ua, _("Failed to connect to File daemon.\n"));
390             return 0;
391          }
392          Dmsg0(200, "Connected to file daemon\n");
393          fd = ua->jcr->file_bsock;
394          bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
395          while (bnet_recv(fd) >= 0) {
396             bsendmsg(ua, "%s", fd->msg);
397          }
398          bnet_sig(fd, BNET_TERMINATE);
399          bnet_close(fd);
400          ua->jcr->file_bsock = NULL;
401       }
402
403       /* Cancel Storage daemon */
404       if (jcr->store_bsock) {
405          if (!ua->jcr->storage) {
406             copy_storage(ua->jcr, jcr->storage);
407          } else {
408             set_storage(ua->jcr, jcr->store);
409          }
410          if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
411             bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
412             return false;
413          }
414          Dmsg0(200, "Connected to storage daemon\n");
415          sd = ua->jcr->store_bsock;
416          bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
417          while (bnet_recv(sd) >= 0) {
418             bsendmsg(ua, "%s", sd->msg);
419          }
420          bnet_sig(sd, BNET_TERMINATE);
421          bnet_close(sd);
422          ua->jcr->store_bsock = NULL;
423       }
424    }
425
426    return true;
427 }
428
429
430 static void job_monitor_destructor(watchdog_t *self)
431 {
432    JCR *control_jcr = (JCR *)self->data;
433
434    free_jcr(control_jcr);
435 }
436
437 static void job_monitor_watchdog(watchdog_t *self)
438 {
439    JCR *control_jcr, *jcr;
440
441    control_jcr = (JCR *)self->data;
442
443    Dmsg1(800, "job_monitor_watchdog %p called\n", self);
444
445    foreach_jcr(jcr) {
446       bool cancel;
447
448       if (jcr->JobId == 0) {
449          Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
450                jcr, jcr->Job);
451          continue;
452       }
453
454       /* check MaxWaitTime */
455       cancel = job_check_maxwaittime(control_jcr, jcr);
456
457       /* check MaxRunTime */
458       cancel |= job_check_maxruntime(control_jcr, jcr);
459
460       if (cancel) {
461          Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
462                jcr, jcr->JobId, jcr->Job);
463
464          UAContext *ua = new_ua_context(jcr);
465          ua->jcr = control_jcr;
466          cancel_job(ua, jcr);
467          free_ua_context(ua);
468
469          Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
470       }
471
472       /* Keep reference counts correct */
473    }
474    endeach_jcr(jcr);
475 }
476
477 /*
478  * Check if the maxwaittime has expired and it is possible
479  *  to cancel the job.
480  */
481 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
482 {
483    bool cancel = false;
484    bool ok_to_cancel = false;
485    JOB *job = jcr->job;
486
487    if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
488        job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
489       return false;
490    } 
491    if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
492          (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
493       ok_to_cancel = true;
494    } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
495          (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
496       ok_to_cancel = true;
497    } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
498          (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
499       ok_to_cancel = true;
500    } else if (job->MaxWaitTime != 0 &&
501          (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
502       ok_to_cancel = true;
503    }
504    if (!ok_to_cancel) {
505       return false;
506    }
507    Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
508          "checking status\n",
509          jcr->JobId, jcr->Job, job->MaxWaitTime);
510    switch (jcr->JobStatus) {
511    case JS_Created:
512    case JS_Blocked:
513    case JS_WaitFD:
514    case JS_WaitSD:
515    case JS_WaitStoreRes:
516    case JS_WaitClientRes:
517    case JS_WaitJobRes:
518    case JS_WaitPriority:
519    case JS_WaitMaxJobs:
520    case JS_WaitStartTime:
521       cancel = true;
522       Dmsg0(200, "JCR blocked in #1\n");
523       break;
524    case JS_Running:
525       Dmsg0(800, "JCR running, checking SD status\n");
526       switch (jcr->SDJobStatus) {
527       case JS_WaitMount:
528       case JS_WaitMedia:
529       case JS_WaitFD:
530          cancel = true;
531          Dmsg0(800, "JCR blocked in #2\n");
532          break;
533       default:
534          Dmsg0(800, "JCR not blocked in #2\n");
535          break;
536       }
537       break;
538    case JS_Terminated:
539    case JS_ErrorTerminated:
540    case JS_Canceled:
541    case JS_FatalError:
542       Dmsg0(800, "JCR already dead in #3\n");
543       break;
544    default:
545       Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
546             jcr->JobStatus);
547    }
548    Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
549          cancel ? "" : "do not ", jcr, jcr->job);
550
551    return cancel;
552 }
553
554 /*
555  * Check if maxruntime has expired and if the job can be
556  *   canceled.
557  */
558 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
559 {
560    bool cancel = false;
561
562    if (jcr->job->MaxRunTime == 0) {
563       return false;
564    }
565    if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
566       Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
567             jcr, jcr->Job, jcr->job->MaxRunTime);
568       return false;
569    }
570
571    switch (jcr->JobStatus) {
572    case JS_Created:
573    case JS_Running:
574    case JS_Blocked:
575    case JS_WaitFD:
576    case JS_WaitSD:
577    case JS_WaitStoreRes:
578    case JS_WaitClientRes:
579    case JS_WaitJobRes:
580    case JS_WaitPriority:
581    case JS_WaitMaxJobs:
582    case JS_WaitStartTime:
583    case JS_Differences:
584       cancel = true;
585       break;
586    case JS_Terminated:
587    case JS_ErrorTerminated:
588    case JS_Canceled:
589    case JS_FatalError:
590       cancel = false;
591       break;
592    default:
593       Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
594             jcr->JobStatus);
595    }
596
597    Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
598          cancel ? "" : "do not ", jcr, jcr->job);
599
600    return cancel;
601 }
602
603
604 /*
605  * Get or create a Client record for this Job
606  */
607 bool get_or_create_client_record(JCR *jcr)
608 {
609    CLIENT_DBR cr;
610
611    memset(&cr, 0, sizeof(cr));
612    bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
613    cr.AutoPrune = jcr->client->AutoPrune;
614    cr.FileRetention = jcr->client->FileRetention;
615    cr.JobRetention = jcr->client->JobRetention;
616    if (!jcr->client_name) {
617       jcr->client_name = get_pool_memory(PM_NAME);
618    }
619    pm_strcpy(jcr->client_name, jcr->client->hdr.name);
620    if (!db_create_client_record(jcr, jcr->db, &cr)) {
621       Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
622          db_strerror(jcr->db));
623       return false;
624    }
625    jcr->jr.ClientId = cr.ClientId;
626    if (cr.Uname[0]) {
627       if (!jcr->client_uname) {
628          jcr->client_uname = get_pool_memory(PM_NAME);
629       }
630       pm_strcpy(jcr->client_uname, cr.Uname);
631    }
632    Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
633       jcr->jr.ClientId);
634    return true;
635 }
636
637 bool get_or_create_fileset_record(JCR *jcr)
638 {
639    FILESET_DBR fsr;
640    /*
641     * Get or Create FileSet record
642     */
643    memset(&fsr, 0, sizeof(FILESET_DBR));
644    bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
645    if (jcr->fileset->have_MD5) {
646       struct MD5Context md5c;
647       unsigned char digest[MD5HashSize];
648       memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
649       MD5Final(digest, &md5c);
650       bin_to_base64(fsr.MD5, (char *)digest, MD5HashSize);
651       bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
652    } else {
653       Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
654    }
655    if (!jcr->fileset->ignore_fs_changes ||
656        !db_get_fileset_record(jcr, jcr->db, &fsr)) {
657       if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
658          Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
659             fsr.FileSet, db_strerror(jcr->db));
660          return false;
661       }
662    }
663    jcr->jr.FileSetId = fsr.FileSetId;
664    bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
665    Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
666       jcr->jr.FileSetId);
667    return true;
668 }
669
670 void init_jcr_job_record(JCR *jcr)
671 {
672    jcr->jr.SchedTime = jcr->sched_time;
673    jcr->jr.StartTime = jcr->start_time;
674    jcr->jr.EndTime = 0;               /* perhaps rescheduled, clear it */
675    jcr->jr.JobType = jcr->JobType;
676    jcr->jr.JobLevel = jcr->JobLevel;
677    jcr->jr.JobStatus = jcr->JobStatus;
678    jcr->jr.JobId = jcr->JobId;
679    bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
680    bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
681 }
682
683 /*
684  * Write status and such in DB
685  */
686 void update_job_end_record(JCR *jcr)
687 {
688    jcr->jr.EndTime = time(NULL);
689    jcr->end_time = jcr->jr.EndTime;
690    jcr->jr.JobId = jcr->JobId;
691    jcr->jr.JobStatus = jcr->JobStatus;
692    jcr->jr.JobFiles = jcr->JobFiles;
693    jcr->jr.JobBytes = jcr->JobBytes;
694    jcr->jr.VolSessionId = jcr->VolSessionId;
695    jcr->jr.VolSessionTime = jcr->VolSessionTime;
696    if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
697       Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
698          db_strerror(jcr->db));
699    }
700 }
701
702 /*
703  * Takes base_name and appends (unique) current
704  *   date and time to form unique job name.
705  *
706  *  Returns: unique job name in jcr->Job
707  *    date/time in jcr->start_time
708  */
709 void create_unique_job_name(JCR *jcr, const char *base_name)
710 {
711    /* Job start mutex */
712    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
713    static time_t last_start_time = 0;
714    time_t now;
715    struct tm tm;
716    char dt[MAX_TIME_LENGTH];
717    char name[MAX_NAME_LENGTH];
718    char *p;
719
720    /* Guarantee unique start time -- maximum one per second, and
721     * thus unique Job Name
722     */
723    P(mutex);                          /* lock creation of jobs */
724    now = time(NULL);
725    while (now == last_start_time) {
726       bmicrosleep(0, 500000);
727       now = time(NULL);
728    }
729    last_start_time = now;
730    V(mutex);                          /* allow creation of jobs */
731    jcr->start_time = now;
732    /* Form Unique JobName */
733    localtime_r(&now, &tm);
734    /* Use only characters that are permitted in Windows filenames */
735    strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
736    bstrncpy(name, base_name, sizeof(name));
737    name[sizeof(name)-22] = 0;          /* truncate if too long */
738    bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
739    /* Convert spaces into underscores */
740    for (p=jcr->Job; *p; p++) {
741       if (*p == ' ') {
742          *p = '_';
743       }
744    }
745 }
746
747 /* Called directly from job rescheduling */
748 void dird_free_jcr_pointers(JCR *jcr)
749 {
750    if (jcr->sd_auth_key) {
751       free(jcr->sd_auth_key);
752       jcr->sd_auth_key = NULL;
753    }
754    if (jcr->where) {
755       free(jcr->where);
756       jcr->where = NULL;
757    }
758    if (jcr->file_bsock) {
759       Dmsg0(200, "Close File bsock\n");
760       bnet_close(jcr->file_bsock);
761       jcr->file_bsock = NULL;
762    }
763    if (jcr->store_bsock) {
764       Dmsg0(200, "Close Store bsock\n");
765       bnet_close(jcr->store_bsock);
766       jcr->store_bsock = NULL;
767    }
768    if (jcr->fname) {
769       Dmsg0(200, "Free JCR fname\n");
770       free_pool_memory(jcr->fname);
771       jcr->fname = NULL;
772    }
773    if (jcr->stime) {
774       Dmsg0(200, "Free JCR stime\n");
775       free_pool_memory(jcr->stime);
776       jcr->stime = NULL;
777    }
778    if (jcr->RestoreBootstrap) {
779       free(jcr->RestoreBootstrap);
780       jcr->RestoreBootstrap = NULL;
781    }
782    if (jcr->client_uname) {
783       free_pool_memory(jcr->client_uname);
784       jcr->client_uname = NULL;
785    }
786    if (jcr->attr) {
787       free_pool_memory(jcr->attr);
788       jcr->attr = NULL;
789    }
790    if (jcr->ar) {
791       free(jcr->ar);
792       jcr->ar = NULL;
793    }
794 }
795
796 /*
797  * Free the Job Control Record if no one is still using it.
798  *  Called from main free_jcr() routine in src/lib/jcr.c so
799  *  that we can do our Director specific cleanup of the jcr.
800  */
801 void dird_free_jcr(JCR *jcr)
802 {
803    Dmsg0(200, "Start dird free_jcr\n");
804
805    dird_free_jcr_pointers(jcr);
806    if (jcr->term_wait_inited) {
807       pthread_cond_destroy(&jcr->term_wait);
808       jcr->term_wait_inited = false;
809    }
810
811    /* Delete lists setup to hold storage pointers */
812    if (jcr->storage) {
813       delete jcr->storage;
814    }
815    jcr->job_end_push.destroy();
816    Dmsg0(200, "End dird free_jcr\n");
817 }
818
819 /*
820  * Set some defaults in the JCR necessary to
821  * run. These items are pulled from the job
822  * definition as defaults, but can be overridden
823  * later either by the Run record in the Schedule resource,
824  * or by the Console program.
825  */
826 void set_jcr_defaults(JCR *jcr, JOB *job)
827 {
828    jcr->job = job;
829    jcr->JobType = job->JobType;
830    switch (jcr->JobType) {
831    case JT_ADMIN:
832    case JT_RESTORE:
833       jcr->JobLevel = L_NONE;
834       break;
835    default:
836       jcr->JobLevel = job->JobLevel;
837       break;
838    }
839    jcr->JobPriority = job->Priority;
840    /* Copy storage definitions -- deleted in dir_free_jcr above */
841    copy_storage(jcr, job->storage);
842    jcr->client = job->client;
843    if (!jcr->client_name) {
844       jcr->client_name = get_pool_memory(PM_NAME);
845    }
846    pm_strcpy(jcr->client_name, jcr->client->hdr.name);
847    jcr->pool = job->pool;
848    jcr->full_pool = job->full_pool;
849    jcr->inc_pool = job->inc_pool;
850    jcr->dif_pool = job->dif_pool;
851    jcr->catalog = job->client->catalog;
852    jcr->fileset = job->fileset;
853    jcr->messages = job->messages;
854    jcr->spool_data = job->spool_data;
855    jcr->write_part_after_job = job->write_part_after_job;
856    if (jcr->RestoreBootstrap) {
857       free(jcr->RestoreBootstrap);
858       jcr->RestoreBootstrap = NULL;
859    }
860    /* This can be overridden by Console program */
861    if (job->RestoreBootstrap) {
862       jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
863    }
864    /* This can be overridden by Console program */
865    jcr->verify_job = job->verify_job;
866    /* If no default level given, set one */
867    if (jcr->JobLevel == 0) {
868       switch (jcr->JobType) {
869       case JT_VERIFY:
870          jcr->JobLevel = L_VERIFY_CATALOG;
871          break;
872       case JT_BACKUP:
873          jcr->JobLevel = L_INCREMENTAL;
874          break;
875       case JT_RESTORE:
876       case JT_ADMIN:
877          jcr->JobLevel = L_NONE;
878          break;
879       default:
880          break;
881       }
882    }
883 }
884
885
886 /* 
887  * Copy the storage definitions from an alist to the JCR
888  */
889 void copy_storage(JCR *jcr, alist *storage)
890 {
891    if (storage) {
892       STORE *st;
893       if (jcr->storage) {
894          delete jcr->storage;
895       }
896       jcr->storage = New(alist(10, not_owned_by_alist));
897       foreach_alist(st, storage) {
898          jcr->storage->append(st);
899       }
900    }               
901    if (jcr->storage) {
902       jcr->store = (STORE *)jcr->storage->first();
903    }
904 }
905
906
907 /* Set storage override */
908 void set_storage(JCR *jcr, STORE *store)
909 {
910    STORE *storage;
911
912    jcr->store = store;
913    foreach_alist(storage, jcr->storage) {
914       if (store == storage) {
915          return;
916       }
917    }
918    /* Store not in list, so add it */
919    jcr->storage->prepend(store);
920 }
921
922 void create_clones(JCR *jcr)
923 {
924    /*
925     * Fire off any clone jobs (run directives)
926     */
927    Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
928    if (!jcr->cloned && jcr->job->run_cmds) {
929       char *runcmd;
930       JOB *job = jcr->job;
931       POOLMEM *cmd = get_pool_memory(PM_FNAME);
932       UAContext *ua = new_ua_context(jcr);
933       ua->batch = true;
934       foreach_alist(runcmd, job->run_cmds) {
935          cmd = edit_job_codes(jcr, cmd, runcmd, "");              
936          Mmsg(ua->cmd, "run %s cloned=yes", cmd);
937          Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
938          parse_ua_args(ua);                 /* parse command */
939          int stat = run_cmd(ua, ua->cmd);
940          if (stat == 0) {
941             Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
942          } else {
943             Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
944          }
945       }
946       free_ua_context(ua);
947       free_pool_memory(cmd);
948    }
949 }
950
951 bool create_restore_bootstrap_file(JCR *jcr)
952 {
953    RESTORE_CTX rx;
954    UAContext *ua;
955    memset(&rx, 0, sizeof(rx));
956    rx.bsr = new_bsr();
957    rx.JobIds = "";                       
958    rx.bsr->JobId = jcr->previous_jr.JobId;
959    ua = new_ua_context(jcr);
960    complete_bsr(ua, rx.bsr);
961    rx.bsr->fi = new_findex();
962    rx.bsr->fi->findex = 1;
963    rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
964    jcr->ExpectedFiles = write_bsr_file(ua, rx);
965    if (jcr->ExpectedFiles == 0) {
966       free_ua_context(ua);
967       free_bsr(rx.bsr);
968       return false;
969    }
970    free_ua_context(ua);
971    free_bsr(rx.bsr);
972    jcr->needs_sd = true;
973    return true;
974 }