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