]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/job.c
03Dec05
[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-2005 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, errstat;
77    JobId_t JobId = 0;
78
79    P(jcr->mutex);
80    sm_check(__FILE__, __LINE__, true);
81    init_msg(jcr, jcr->messages);
82
83    /* Initialize termination condition variable */
84    if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
85       berrno be;
86       Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.strerror(errstat));
87       goto bail_out;
88    }
89    jcr->term_wait_inited = true;
90
91
92    /*
93     * Open database
94     */
95    Dmsg0(50, "Open database\n");
96    jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
97                             jcr->catalog->db_password, jcr->catalog->db_address,
98                             jcr->catalog->db_port, jcr->catalog->db_socket,
99                             jcr->catalog->mult_db_connections);
100    if (!jcr->db || !db_open_database(jcr, jcr->db)) {
101       Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
102                  jcr->catalog->db_name);
103       if (jcr->db) {
104          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
105       }
106       goto bail_out;
107    }
108    Dmsg0(50, "DB opened\n");
109
110    /*
111     * Create Job record
112     */
113    create_unique_job_name(jcr, jcr->job->hdr.name);
114    set_jcr_job_status(jcr, JS_Created);
115    init_jcr_job_record(jcr);
116    if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
117       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
118       goto bail_out;
119    }
120    JobId = jcr->JobId = jcr->jr.JobId;
121    Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
122        jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
123
124    generate_daemon_event(jcr, "JobStart");
125
126    if (!get_or_create_client_record(jcr)) {
127       goto bail_out;
128    }
129
130    if (job_canceled(jcr)) {
131       goto bail_out;
132    }
133
134    Dmsg0(200, "Add jrc to work queue\n");
135
136    /* Queue the job to be run */
137    if ((stat = jobq_add(&job_queue, jcr)) != 0) {
138       berrno be;
139       Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.strerror(stat));
140       JobId = 0;
141       goto bail_out;
142    }
143    Dmsg0(100, "Done run_job()\n");
144
145    V(jcr->mutex);
146    return JobId;
147
148 bail_out:
149    if (jcr->fname) {
150       free_memory(jcr->fname);
151       jcr->fname = NULL;
152    }
153    V(jcr->mutex);
154    return JobId;
155 }
156
157
158 /*
159  * This is the engine called by jobq.c:jobq_add() when we were pulled
160  *  from the work queue.
161  *  At this point, we are running in our own thread and all
162  *    necessary resources are allocated -- see jobq.c
163  */
164 static void *job_thread(void *arg)
165 {
166    JCR *jcr = (JCR *)arg;
167
168    jcr->my_thread_id = pthread_self();
169    pthread_detach(jcr->my_thread_id);
170    sm_check(__FILE__, __LINE__, true);
171
172    Dmsg0(200, "=====Start Job=========\n");
173    jcr->start_time = time(NULL);      /* set the real start time */
174    jcr->jr.StartTime = jcr->start_time;
175
176    if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
177        (utime_t)(jcr->start_time - jcr->sched_time)) {
178       Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
179       set_jcr_job_status(jcr, JS_Canceled);
180    }
181
182    /*                                
183     * Note, we continue, even if the job is canceled above. This
184     *  will permit proper setting of the job start record and
185     *  the error (cancel) will be picked up below.
186     */
187
188    generate_job_event(jcr, "JobInit");
189    set_jcr_job_status(jcr, JS_Running);   /* this will be set only if no error */
190
191    if (!jcr->fname) {
192       jcr->fname = get_pool_memory(PM_FNAME);
193    }
194
195    /*
196     * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
197     *  this allows us to setup a proper job start record for restarting
198     *  in case of later errors.
199     */
200    switch (jcr->JobType) {
201    case JT_BACKUP:
202       if (!do_backup_init(jcr)) {
203          backup_cleanup(jcr, JS_ErrorTerminated);
204       }
205       break;
206    case JT_VERIFY:
207       if (!do_verify_init(jcr)) {
208          verify_cleanup(jcr, JS_ErrorTerminated);
209       }
210       break;
211    case JT_RESTORE:
212       if (!do_restore_init(jcr)) {
213          restore_cleanup(jcr, JS_ErrorTerminated);
214       }
215       break;
216    case JT_ADMIN:
217       if (!do_admin_init(jcr)) {
218          admin_cleanup(jcr, JS_ErrorTerminated);
219       }
220       break;
221    case JT_MIGRATE:
222    case JT_COPY:
223    case JT_ARCHIVE:
224       if (!do_mac_init(jcr)) {             /* migration, archive, copy */
225          mac_cleanup(jcr, JS_ErrorTerminated);
226       }
227       break;
228    default:
229       Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
230       set_jcr_job_status(jcr, JS_ErrorTerminated);
231       break;
232    }
233
234    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
235       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
236    }
237
238    if (job_canceled(jcr)) {
239       update_job_end_record(jcr);
240
241    } else {
242
243       /* Run Job */
244       if (jcr->job->RunBeforeJob) {
245          POOLMEM *before = get_pool_memory(PM_FNAME);
246          int status;
247          BPIPE *bpipe;
248          char line[MAXSTRING];
249
250          before = edit_job_codes(jcr, before, jcr->job->RunBeforeJob, "");
251          bpipe = open_bpipe(before, 0, "r");
252          free_pool_memory(before);
253          while (fgets(line, sizeof(line), bpipe->rfd)) {
254             Jmsg(jcr, M_INFO, 0, _("RunBefore: %s"), line);
255          }
256          status = close_bpipe(bpipe);
257          if (status != 0) {
258             berrno be;
259             Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob error: ERR=%s\n"), be.strerror(status));
260             set_jcr_job_status(jcr, JS_FatalError);
261             update_job_end_record(jcr);
262             goto bail_out;
263          }
264       }
265
266       generate_job_event(jcr, "JobRun");
267
268       switch (jcr->JobType) {
269       case JT_BACKUP:
270          if (do_backup(jcr)) {
271             do_autoprune(jcr);
272          } else {
273             backup_cleanup(jcr, JS_ErrorTerminated);
274          }
275          break;
276       case JT_VERIFY:
277          if (do_verify(jcr)) {
278             do_autoprune(jcr);
279          } else {
280             verify_cleanup(jcr, JS_ErrorTerminated);
281          }
282          break;
283       case JT_RESTORE:
284          if (do_restore(jcr)) {
285             do_autoprune(jcr);
286          } else {
287             restore_cleanup(jcr, JS_ErrorTerminated);
288          }
289          break;
290       case JT_ADMIN:
291          if (do_admin(jcr)) {
292             do_autoprune(jcr);
293          } else {
294             admin_cleanup(jcr, JS_ErrorTerminated);
295          }
296          break;
297       case JT_MIGRATE:
298       case JT_COPY:
299       case JT_ARCHIVE:
300          if (do_mac(jcr)) {              /* migration, archive, copy */
301             do_autoprune(jcr);
302          } else {
303             mac_cleanup(jcr, JS_ErrorTerminated);
304          }
305          break;
306       default:
307          Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
308          break;
309       }
310       if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
311           (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
312          POOLMEM *after = get_pool_memory(PM_FNAME);
313          int status;
314          BPIPE *bpipe;
315          char line[MAXSTRING];
316
317          if (jcr->JobStatus == JS_Terminated) {
318             after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
319          } else {
320             after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
321          }
322          bpipe = open_bpipe(after, 0, "r");
323          free_pool_memory(after);
324          while (fgets(line, sizeof(line), bpipe->rfd)) {
325             Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
326          }
327          status = close_bpipe(bpipe);
328          /*
329           * Note, if we get an error here, do not mark the
330           *  job in error, simply report the error condition.
331           */
332          if (status != 0) {
333             berrno be;
334             if (jcr->JobStatus == JS_Terminated) {
335                Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror(status));
336             } else {
337                Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror(status));
338             }
339          }
340       }
341       /* Send off any queued messages */
342       if (jcr->msg_queue->size() > 0) {
343          dequeue_messages(jcr);
344       }
345    }
346
347 bail_out:
348    generate_daemon_event(jcr, "JobEnd");
349    Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
350    sm_check(__FILE__, __LINE__, true);
351    return NULL;
352 }
353
354
355 /*
356  * Cancel a job -- typically called by the UA (Console program), but may also
357  *              be called by the job watchdog.
358  *
359  *  Returns: true  if cancel appears to be successful
360  *           false on failure. Message sent to ua->jcr.
361  */
362 bool cancel_job(UAContext *ua, JCR *jcr)
363 {
364    BSOCK *sd, *fd;
365
366    set_jcr_job_status(jcr, JS_Canceled);
367
368    switch (jcr->JobStatus) {
369    case JS_Created:
370    case JS_WaitJobRes:
371    case JS_WaitClientRes:
372    case JS_WaitStoreRes:
373    case JS_WaitPriority:
374    case JS_WaitMaxJobs:
375    case JS_WaitStartTime:
376       bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
377               jcr->JobId, jcr->Job);
378       jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
379       return true;
380
381    default:
382
383       /* Cancel File daemon */
384       if (jcr->file_bsock) {
385          ua->jcr->client = jcr->client;
386          if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
387             bsendmsg(ua, _("Failed to connect to File daemon.\n"));
388             return 0;
389          }
390          Dmsg0(200, "Connected to file daemon\n");
391          fd = ua->jcr->file_bsock;
392          bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
393          while (bnet_recv(fd) >= 0) {
394             bsendmsg(ua, "%s", fd->msg);
395          }
396          bnet_sig(fd, BNET_TERMINATE);
397          bnet_close(fd);
398          ua->jcr->file_bsock = NULL;
399       }
400
401       /* Cancel Storage daemon */
402       if (jcr->store_bsock) {
403          if (!ua->jcr->storage) {
404             copy_storage(ua->jcr, jcr);
405          } else {
406             set_storage(ua->jcr, jcr->store);
407          }
408          if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
409             bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
410             return false;
411          }
412          Dmsg0(200, "Connected to storage daemon\n");
413          sd = ua->jcr->store_bsock;
414          bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
415          while (bnet_recv(sd) >= 0) {
416             bsendmsg(ua, "%s", sd->msg);
417          }
418          bnet_sig(sd, BNET_TERMINATE);
419          bnet_close(sd);
420          ua->jcr->store_bsock = NULL;
421       }
422    }
423
424    return true;
425 }
426
427
428 static void job_monitor_destructor(watchdog_t *self)
429 {
430    JCR *control_jcr = (JCR *) self->data;
431
432    free_jcr(control_jcr);
433 }
434
435 static void job_monitor_watchdog(watchdog_t *self)
436 {
437    JCR *control_jcr, *jcr;
438
439    control_jcr = (JCR *)self->data;
440
441    Dmsg1(800, "job_monitor_watchdog %p called\n", self);
442
443    foreach_jcr(jcr) {
444       bool cancel;
445
446       if (jcr->JobId == 0) {
447          Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
448                jcr, jcr->Job);
449          /* Keep reference counts correct */
450          free_jcr(jcr);
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          Dmsg1(800, "Have cancelled JCR %p\n", jcr);
470       }
471
472       /* Keep reference counts correct */
473       free_jcr(jcr);
474    }
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 signature[16];
648       memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
649       MD5Final(signature, &md5c);
650       bin_to_base64(fsr.MD5, (char *)signature, 16); /* encode 16 bytes */
651       bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
652    } else {
653       Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 signature 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->term_wait_inited) {
787       pthread_cond_destroy(&jcr->term_wait);
788       jcr->term_wait_inited = false;
789    }
790    if (jcr->attr) {
791       free_pool_memory(jcr->attr);
792       jcr->attr = NULL;
793    }
794    if (jcr->ar) {
795       free(jcr->ar);
796       jcr->ar = NULL;
797    }
798 }
799
800 /*
801  * Free the Job Control Record if no one is still using it.
802  *  Called from main free_jcr() routine in src/lib/jcr.c so
803  *  that we can do our Director specific cleanup of the jcr.
804  */
805 void dird_free_jcr(JCR *jcr)
806 {
807    Dmsg0(200, "Start dird free_jcr\n");
808
809    dird_free_jcr_pointers(jcr);
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    STORE *st;
829    jcr->job = job;
830    jcr->JobType = job->JobType;
831    switch (jcr->JobType) {
832    case JT_ADMIN:
833    case JT_RESTORE:
834       jcr->JobLevel = L_NONE;
835       break;
836    default:
837       jcr->JobLevel = job->JobLevel;
838       break;
839    }
840    jcr->JobPriority = job->Priority;
841    /* Copy storage definitions -- deleted in dir_free_jcr above */
842    if (job->storage) {
843       if (jcr->storage) {
844          delete jcr->storage;
845       }
846       jcr->storage = New(alist(10, not_owned_by_alist));
847       foreach_alist(st, job->storage) {
848          jcr->storage->append(st);
849       }
850    }
851    if (jcr->storage) {
852       jcr->store = (STORE *)jcr->storage->first();
853    }
854    jcr->client = job->client;
855    if (!jcr->client_name) {
856       jcr->client_name = get_pool_memory(PM_NAME);
857    }
858    pm_strcpy(jcr->client_name, jcr->client->hdr.name);
859    jcr->pool = job->pool;
860    jcr->full_pool = job->full_pool;
861    jcr->inc_pool = job->inc_pool;
862    jcr->dif_pool = job->dif_pool;
863    jcr->catalog = job->client->catalog;
864    jcr->fileset = job->fileset;
865    jcr->messages = job->messages;
866    jcr->spool_data = job->spool_data;
867    jcr->write_part_after_job = job->write_part_after_job;
868    if (jcr->RestoreBootstrap) {
869       free(jcr->RestoreBootstrap);
870       jcr->RestoreBootstrap = NULL;
871    }
872    /* This can be overridden by Console program */
873    if (job->RestoreBootstrap) {
874       jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
875    }
876    /* This can be overridden by Console program */
877    jcr->verify_job = job->verify_job;
878    /* If no default level given, set one */
879    if (jcr->JobLevel == 0) {
880       switch (jcr->JobType) {
881       case JT_VERIFY:
882          jcr->JobLevel = L_VERIFY_CATALOG;
883          break;
884       case JT_BACKUP:
885          jcr->JobLevel = L_INCREMENTAL;
886          break;
887       case JT_RESTORE:
888       case JT_ADMIN:
889          jcr->JobLevel = L_NONE;
890          break;
891       default:
892          break;
893       }
894    }
895 }
896
897 /*
898  * copy the storage definitions from an old JCR to a new one
899  */
900 void copy_storage(JCR *new_jcr, JCR *old_jcr)
901 {
902    if (old_jcr->storage) {
903       STORE *st;
904       if (old_jcr->storage) {
905          delete old_jcr->storage;
906       }
907       new_jcr->storage = New(alist(10, not_owned_by_alist));
908       foreach_alist(st, old_jcr->storage) {
909          new_jcr->storage->append(st);
910       }
911    }
912    if (old_jcr->store) {
913       new_jcr->store = old_jcr->store;
914    } else if (new_jcr->storage) {
915       new_jcr->store = (STORE *)new_jcr->storage->first();
916    }
917 }
918
919 /* Set storage override */
920 void set_storage(JCR *jcr, STORE *store)
921 {
922    STORE *storage;
923
924    jcr->store = store;
925    foreach_alist(storage, jcr->storage) {
926       if (store == storage) {
927          return;
928       }
929    }
930    /* Store not in list, so add it */
931    jcr->storage->prepend(store);
932 }