]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/jcr.c
ebl Add Plugin debug after a fatal signal.
[bacula/bacula] / bacula / src / lib / jcr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Manipulation routines for Job Control Records and
30  *  handling of last_jobs_list.
31  *
32  *  Kern E. Sibbald, December 2000
33  *
34  *  Version $Id$
35  *
36  *  These routines are thread safe.
37  *
38  *  The job list routines were re-written in May 2005 to
39  *  eliminate the global lock while traversing the list, and
40  *  to use the dlist subroutines.  The locking is now done
41  *  on the list each time the list is modified or traversed.
42  *  That is it is "micro-locked" rather than globally locked.
43  *  The result is that there is one lock/unlock for each entry
44  *  in the list while traversing it rather than a single lock
45  *  at the beginning of a traversal and one at the end.  This
46  *  incurs slightly more overhead, but effectively eliminates 
47  *  the possibilty of race conditions.  In addition, with the
48  *  exception of the global locking of the list during the
49  *  re-reading of the config file, no recursion is needed.
50  *
51  */
52
53 #include "bacula.h"
54 #include "jcr.h"
55
56 const int dbglvl = 3400;
57
58 /* External variables we reference */
59 extern time_t watchdog_time;
60
61 /* External referenced functions */
62 void free_bregexps(alist *bregexps);
63
64 /* Forward referenced functions */
65 extern "C" void timeout_handler(int sig);
66 static void jcr_timeout_check(watchdog_t *self);
67 #ifdef TRACE_JCR_CHAIN
68 static void b_lock_jcr_chain(const char *filen, int line);
69 static void b_unlock_jcr_chain(const char *filen, int line);
70 #define lock_jcr_chain() b_lock_jcr_chain(__FILE__, __LINE__);
71 #define unlock_jcr_chain() b_unlock_jcr_chain(__FILE__, __LINE__);
72 #else
73 static void lock_jcr_chain();
74 static void unlock_jcr_chain();
75 #endif
76
77
78 int num_jobs_run;
79 dlist *last_jobs = NULL;
80 const int max_last_jobs = 10;
81  
82 static dlist *jcrs = NULL;            /* JCR chain */
83 static pthread_mutex_t jcr_lock = PTHREAD_MUTEX_INITIALIZER;
84
85 static pthread_mutex_t job_start_mutex = PTHREAD_MUTEX_INITIALIZER;
86
87 static pthread_mutex_t last_jobs_mutex = PTHREAD_MUTEX_INITIALIZER;
88
89 static pthread_key_t jcr_key;         /* Pointer to jcr for each thread */
90
91 pthread_once_t key_once = PTHREAD_ONCE_INIT; 
92
93
94 void lock_jobs()
95 {
96    P(job_start_mutex);
97 }
98
99 void unlock_jobs()
100 {
101    V(job_start_mutex);
102 }
103
104 void init_last_jobs_list()
105 {
106    JCR *jcr = NULL;
107    struct s_last_job *job_entry = NULL;
108    if (!last_jobs) {
109       last_jobs = New(dlist(job_entry, &job_entry->link));
110    }
111    if (!jcrs) {
112       jcrs = New(dlist(jcr, &jcr->link));
113    }
114 }
115
116 void term_last_jobs_list()
117 {
118    if (last_jobs) {
119       lock_last_jobs_list();
120       while (!last_jobs->empty()) {
121          void *je = last_jobs->first();
122          last_jobs->remove(je);
123          free(je);
124       }
125       delete last_jobs;
126       last_jobs = NULL;
127       unlock_last_jobs_list();
128    }
129    if (jcrs) {
130       delete jcrs;
131       jcrs = NULL;
132    }
133 }
134
135 bool read_last_jobs_list(int fd, uint64_t addr)
136 {
137    struct s_last_job *je, job;
138    uint32_t num;
139    bool ok = true;
140
141    Dmsg1(100, "read_last_jobs seek to %d\n", (int)addr);
142    if (addr == 0 || lseek(fd, (boffset_t)addr, SEEK_SET) < 0) {
143       return false;
144    }
145    if (read(fd, &num, sizeof(num)) != sizeof(num)) {
146       return false;
147    }
148    Dmsg1(100, "Read num_items=%d\n", num);
149    if (num > 4 * max_last_jobs) {  /* sanity check */
150       return false;
151    }
152    lock_last_jobs_list();
153    for ( ; num; num--) {
154       if (read(fd, &job, sizeof(job)) != sizeof(job)) {
155          berrno be;
156          Pmsg1(000, "Read job entry. ERR=%s\n", be.bstrerror());
157          ok = false;
158          break;
159       }
160       if (job.JobId > 0) {
161          je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
162          memcpy((char *)je, (char *)&job, sizeof(job));
163          if (!last_jobs) {
164             init_last_jobs_list();
165          }
166          last_jobs->append(je);
167          if (last_jobs->size() > max_last_jobs) {
168             je = (struct s_last_job *)last_jobs->first();
169             last_jobs->remove(je);
170             free(je);
171          }
172       }
173    }
174    unlock_last_jobs_list();
175    return ok;
176 }
177
178 uint64_t write_last_jobs_list(int fd, uint64_t addr)
179 {
180    struct s_last_job *je;
181    uint32_t num;
182    ssize_t stat;
183
184    Dmsg1(100, "write_last_jobs seek to %d\n", (int)addr);
185    if (lseek(fd, (boffset_t)addr, SEEK_SET) < 0) {
186       return 0;
187    }
188    if (last_jobs) {
189       lock_last_jobs_list();
190       /* First record is number of entires */
191       num = last_jobs->size();
192       if (write(fd, &num, sizeof(num)) != sizeof(num)) {
193          berrno be;
194          Pmsg1(000, "Error writing num_items: ERR=%s\n", be.bstrerror());
195          goto bail_out;
196       }
197       foreach_dlist(je, last_jobs) {
198          if (write(fd, je, sizeof(struct s_last_job)) != sizeof(struct s_last_job)) {
199             berrno be;
200             Pmsg1(000, "Error writing job: ERR=%s\n", be.bstrerror());
201             goto bail_out;
202          }
203       }
204       unlock_last_jobs_list();
205    }
206    /* Return current address */
207    stat = lseek(fd, 0, SEEK_CUR);
208    if (stat < 0) {
209       stat = 0;
210    }
211    return stat;
212
213 bail_out:
214    unlock_last_jobs_list();
215    return 0;
216 }
217
218 void lock_last_jobs_list()
219 {
220    P(last_jobs_mutex);
221 }
222
223 void unlock_last_jobs_list()
224 {
225    V(last_jobs_mutex);
226 }
227
228 /* Get an ASCII representation of the Operation being performed as an english Noun */
229 const char *JCR::get_OperationName()
230 {
231    switch(m_JobType) {
232    case JT_BACKUP:
233       return _("Backup");
234    case JT_VERIFY:
235       return _("Verifying");
236    case JT_RESTORE:
237       return _("Restoring");
238    case JT_ARCHIVE:
239       return _("Archiving");
240    case JT_COPY:
241       return _("Copying");
242    case JT_MIGRATE:
243       return _("Migration");
244    case JT_SCAN:
245       return _("Scanning");
246    default:
247       return _("Unknown operation");
248    }
249 }
250
251 /* Get an ASCII representation of the Action being performed either an english Verb or Adjective */
252 const char *JCR::get_ActionName(bool past)
253 {
254    switch(m_JobType) {
255    case JT_BACKUP:
256       return _("backup");
257    case JT_VERIFY:
258       return (past == true) ? _("verified") : _("verify");
259    case JT_RESTORE:
260       return (past == true) ? _("restored") : _("restore");
261    case JT_ARCHIVE:
262       return (past == true) ? _("archived") : _("archive");
263    case JT_COPY:
264       return (past == true) ? _("copied") : _("copy");
265    case JT_MIGRATE:
266       return (past == true) ? _("migrated") : _("migrate");
267    case JT_SCAN:
268       return (past == true) ? _("scanned") : _("scan");
269    default:
270       return _("unknown action");
271    }
272 }
273
274 /* Set Job type in JCR and also set appropriate read flag */
275 void JCR::set_JobType(int32_t JobType)
276 {
277    m_JobType = JobType;
278 }
279
280 /* Set Job level in JCR and also set appropriate read flag */
281 void JCR::set_JobLevel(int32_t JobLevel)
282 {
283    m_JobLevel = JobLevel;
284 }
285
286 bool JCR::JobReads()
287 {
288    switch (m_JobType) {
289    case JT_VERIFY:
290    case JT_RESTORE:
291    case JT_COPY:
292    case JT_MIGRATE:
293       return true;
294    case JT_BACKUP:
295       if (m_JobLevel == L_VIRTUAL_FULL) {
296          return true;
297       }
298       break;
299    default:
300       break;
301    }
302    return false;
303 }
304
305 /*
306  * Push a subroutine address into the job end callback stack
307  */
308 void job_end_push(JCR *jcr, void job_end_cb(JCR *jcr,void *), void *ctx)
309 {
310    jcr->job_end_push.append((void *)job_end_cb);
311    jcr->job_end_push.append(ctx);
312 }
313
314 /* Pop each job_end subroutine and call it */
315 static void job_end_pop(JCR *jcr)
316 {
317    void (*job_end_cb)(JCR *jcr, void *ctx);
318    void *ctx;
319    for (int i=jcr->job_end_push.size()-1; i > 0; ) {
320       ctx = jcr->job_end_push.get(i--);
321       job_end_cb = (void (*)(JCR *,void *))jcr->job_end_push.get(i--);
322       job_end_cb(jcr, ctx);
323    }
324 }
325
326 void create_jcr_key()
327 {
328    int status = pthread_key_create(&jcr_key, NULL);
329    if (status != 0) {
330       berrno be;
331       Jmsg1(NULL, M_ABORT, 0, _("pthread key create failed: ERR=%s\n"),
332             be.bstrerror(status));
333    }
334 }
335
336 /*
337  * Create a Job Control Record and link it into JCR chain
338  * Returns newly allocated JCR
339  * Note, since each daemon has a different JCR, he passes
340  *  us the size.
341  */
342 JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr)
343 {
344    JCR *jcr;
345    MQUEUE_ITEM *item = NULL;
346    struct sigaction sigtimer;
347    int status;
348
349    Dmsg0(dbglvl, "Enter new_jcr\n");
350    status = pthread_once(&key_once, create_jcr_key);
351    if (status != 0) {
352       berrno be;
353       Jmsg1(NULL, M_ABORT, 0, _("pthread_once failed. ERR=%s\n"), be.bstrerror(status));
354    }
355    jcr = (JCR *)malloc(size);
356    memset(jcr, 0, size);
357    jcr->my_thread_id = pthread_self();
358    jcr->msg_queue = New(dlist(item, &item->link));
359    jcr->job_end_push.init(1, false);
360    jcr->sched_time = time(NULL);
361    jcr->daemon_free_jcr = daemon_free_jcr;    /* plug daemon free routine */
362    jcr->init_mutex();
363    jcr->inc_use_count();   
364    jcr->VolumeName = get_pool_memory(PM_FNAME);
365    jcr->VolumeName[0] = 0;
366    jcr->errmsg = get_pool_memory(PM_MESSAGE);
367    jcr->errmsg[0] = 0;
368    /* Setup some dummy values */
369    bstrncpy(jcr->Job, "*System*", sizeof(jcr->Job));
370    jcr->JobId = 0;
371    jcr->set_JobType(JT_SYSTEM);          /* internal job until defined */
372    jcr->set_JobLevel(L_NONE);
373    set_jcr_job_status(jcr, JS_Created);       /* ready to run */
374    set_jcr_in_tsd(jcr);
375    sigtimer.sa_flags = 0;
376    sigtimer.sa_handler = timeout_handler;
377    sigfillset(&sigtimer.sa_mask);
378    sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL);
379
380    /*
381     * Locking jobs is a global lock that is needed
382     * so that the Director can stop new jobs from being
383     * added to the jcr chain while it processes a new
384     * conf file and does the job_end_push().
385     */
386    lock_jobs();
387    lock_jcr_chain();
388    if (!jcrs) {
389       jcrs = New(dlist(jcr, &jcr->link));
390    }
391    jcrs->append(jcr);
392    unlock_jcr_chain();
393    unlock_jobs();
394
395    return jcr;
396 }
397
398
399 /*
400  * Remove a JCR from the chain
401  * NOTE! The chain must be locked prior to calling
402  *       this routine.
403  */
404 static void remove_jcr(JCR *jcr)
405 {
406    Dmsg0(dbglvl, "Enter remove_jcr\n");
407    if (!jcr) {
408       Emsg0(M_ABORT, 0, _("NULL jcr.\n"));
409    }
410    jcrs->remove(jcr);
411    Dmsg0(dbglvl, "Leave remove_jcr\n");
412 }
413
414 /*
415  * Free stuff common to all JCRs.  N.B. Be careful to include only
416  *  generic stuff in the common part of the jcr.
417  */
418 static void free_common_jcr(JCR *jcr)
419 {
420    jcr->destroy_mutex();
421
422    if (jcr->msg_queue) {
423       delete jcr->msg_queue;
424       jcr->msg_queue = NULL;
425    }
426    close_msg(jcr);                    /* close messages for this job */
427
428    /* do this after closing messages */
429    if (jcr->client_name) {
430       free_pool_memory(jcr->client_name);
431       jcr->client_name = NULL;
432    }
433
434    if (jcr->attr) {
435       free_pool_memory(jcr->attr);
436       jcr->attr = NULL;
437    }
438
439    if (jcr->sd_auth_key) {
440       free(jcr->sd_auth_key);
441       jcr->sd_auth_key = NULL;
442    }
443    if (jcr->VolumeName) {
444       free_pool_memory(jcr->VolumeName);
445       jcr->VolumeName = NULL;
446    }
447
448    if (jcr->dir_bsock) {
449       bnet_close(jcr->dir_bsock);
450       jcr->dir_bsock = NULL;
451    }
452    if (jcr->errmsg) {
453       free_pool_memory(jcr->errmsg);
454       jcr->errmsg = NULL;
455    }
456    if (jcr->where) {
457       free(jcr->where);
458       jcr->where = NULL;
459    }
460    if (jcr->RegexWhere) {
461       free(jcr->RegexWhere);
462       jcr->RegexWhere = NULL;
463    }
464    if (jcr->where_bregexp) {
465       free_bregexps(jcr->where_bregexp);
466       delete jcr->where_bregexp;
467       jcr->where_bregexp = NULL;
468    }
469    if (jcr->cached_path) {
470       free_pool_memory(jcr->cached_path);
471       jcr->cached_path = NULL;
472       jcr->cached_pnl = 0;
473    }
474    if (jcr->id_list) {
475       free_guid_list(jcr->id_list);
476       jcr->id_list = NULL;
477    }
478    /* Invalidate the tsd jcr data */
479    set_jcr_in_tsd(INVALID_JCR);
480    free(jcr);
481 }
482
483 /*
484  * Global routine to free a jcr
485  */
486 #ifdef DEBUG
487 void b_free_jcr(const char *file, int line, JCR *jcr)
488 {
489    struct s_last_job *je;
490
491    Dmsg3(dbglvl, "Enter free_jcr jid=%u from %s:%d\n", jcr->JobId, file, line);
492
493 #else
494
495 void free_jcr(JCR *jcr)
496 {
497    struct s_last_job *je;
498
499    Dmsg3(dbglvl, "Enter free_jcr jid=%u use_count=%d Job=%s\n", 
500          jcr->JobId, jcr->use_count(), jcr->Job);
501
502 #endif
503
504    dequeue_messages(jcr);
505    lock_jcr_chain();
506    jcr->dec_use_count();              /* decrement use count */
507    if (jcr->use_count() < 0) {
508       Jmsg2(jcr, M_ERROR, 0, _("JCR use_count=%d JobId=%d\n"),
509          jcr->use_count(), jcr->JobId);
510    }
511    if (jcr->JobId > 0) {
512       Dmsg3(dbglvl, "Dec free_jcr jid=%u use_count=%d Job=%s\n", 
513          jcr->JobId, jcr->use_count(), jcr->Job);
514    }
515    if (jcr->use_count() > 0) {          /* if in use */
516       unlock_jcr_chain();
517       return;
518    }
519    if (jcr->JobId > 0) {
520       Dmsg3(dbglvl, "remove jcr jid=%u use_count=%d Job=%s\n", 
521             jcr->JobId, jcr->use_count(), jcr->Job);
522    }
523    remove_jcr(jcr);                   /* remove Jcr from chain */
524
525    job_end_pop(jcr);                  /* pop and call hooked routines */
526
527    Dmsg1(dbglvl, "End job=%d\n", jcr->JobId);
528
529    /* Keep some statistics */
530    switch (jcr->get_JobType()) {
531    case JT_BACKUP:
532    case JT_VERIFY:
533    case JT_RESTORE:
534    case JT_MIGRATE:
535    case JT_COPY:
536    case JT_ADMIN:
537       /* Keep list of last jobs, but not Console where JobId==0 */
538       if (jcr->JobId > 0) {
539          lock_last_jobs_list();
540          num_jobs_run++;
541          je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
542          memset(je, 0, sizeof(struct s_last_job));  /* zero in case unset fields */
543          je->Errors = jcr->Errors;
544          je->JobType = jcr->get_JobType();
545          je->JobId = jcr->JobId;
546          je->VolSessionId = jcr->VolSessionId;
547          je->VolSessionTime = jcr->VolSessionTime;
548          bstrncpy(je->Job, jcr->Job, sizeof(je->Job));
549          je->JobFiles = jcr->JobFiles;
550          je->JobBytes = jcr->JobBytes;
551          je->JobStatus = jcr->JobStatus;
552          je->JobLevel = jcr->get_JobLevel();
553          je->start_time = jcr->start_time;
554          je->end_time = time(NULL);
555
556          if (!last_jobs) {
557             init_last_jobs_list();
558          }
559          last_jobs->append(je);
560          if (last_jobs->size() > max_last_jobs) {
561             je = (struct s_last_job *)last_jobs->first();
562             last_jobs->remove(je);
563             free(je);
564          }
565          unlock_last_jobs_list();
566       }
567       break;
568    default:
569       break;
570    }
571
572    if (jcr->daemon_free_jcr) {
573       jcr->daemon_free_jcr(jcr);      /* call daemon free routine */
574    }
575
576    unlock_jcr_chain();
577    free_common_jcr(jcr);
578    close_msg(NULL);                   /* flush any daemon messages */
579    garbage_collect_memory_pool();
580    Dmsg0(dbglvl, "Exit free_jcr\n");
581 }
582
583 void set_jcr_in_tsd(JCR *jcr)
584 {
585    int status = pthread_setspecific(jcr_key, (void *)jcr);
586    if (status != 0) {
587       berrno be;
588       Jmsg1(jcr, M_ABORT, 0, _("pthread_setspecific failed: ERR=%s\n"), be.bstrerror(status));
589    }
590 }
591
592 JCR *get_jcr_from_tsd()
593 {
594    JCR *jcr = (JCR *)pthread_getspecific(jcr_key);
595 // printf("get_jcr_from_tsd: jcr=%p\n", jcr);
596    /* set any INVALID_JCR to NULL which the rest of Bacula understands */
597    if (jcr == INVALID_JCR) {
598       jcr = NULL;
599    }
600    return jcr;
601 }
602
603  
604 /*
605  * Find which JobId corresponds to the current thread
606  */
607 uint32_t get_jobid_from_tsd()
608 {
609    JCR *jcr;
610    uint32_t JobId = 0;
611    jcr = get_jcr_from_tsd();
612 // printf("get_jobid_from_tsr: jcr=%p\n", jcr);
613    if (jcr) {
614       JobId = (uint32_t)jcr->JobId;
615    }
616    return JobId;
617 }
618
619 /*
620  * Given a JobId, find the JCR
621  *   Returns: jcr on success
622  *            NULL on failure
623  */
624 JCR *get_jcr_by_id(uint32_t JobId)
625 {
626    JCR *jcr;
627
628    foreach_jcr(jcr) {
629       if (jcr->JobId == JobId) {
630          jcr->inc_use_count();
631          Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", 
632             jcr->JobId, jcr->use_count(), jcr->Job);
633          break;
634       }
635    }
636    endeach_jcr(jcr);
637    return jcr;
638 }
639
640 /*
641  * Given a SessionId and SessionTime, find the JCR
642  *   Returns: jcr on success
643  *            NULL on failure
644  */
645 JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime)
646 {
647    JCR *jcr;
648
649    foreach_jcr(jcr) {
650       if (jcr->VolSessionId == SessionId &&
651           jcr->VolSessionTime == SessionTime) {
652          jcr->inc_use_count();
653          Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", 
654             jcr->JobId, jcr->use_count(), jcr->Job);
655          break;
656       }
657    }
658    endeach_jcr(jcr);
659    return jcr;
660 }
661
662
663 /*
664  * Given a Job, find the JCR
665  *  compares on the number of characters in Job
666  *  thus allowing partial matches.
667  *   Returns: jcr on success
668  *            NULL on failure
669  */
670 JCR *get_jcr_by_partial_name(char *Job)
671 {
672    JCR *jcr;
673    int len;
674
675    if (!Job) {
676       return NULL;
677    }
678    len = strlen(Job);
679    foreach_jcr(jcr) {
680       if (strncmp(Job, jcr->Job, len) == 0) {
681          jcr->inc_use_count();
682          Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", 
683             jcr->JobId, jcr->use_count(), jcr->Job);
684          break;
685       }
686    }
687    endeach_jcr(jcr);
688    return jcr;
689 }
690
691
692 /*
693  * Given a Job, find the JCR
694  *  requires an exact match of names.
695  *   Returns: jcr on success
696  *            NULL on failure
697  */
698 JCR *get_jcr_by_full_name(char *Job)
699 {
700    JCR *jcr;
701
702    if (!Job) {
703       return NULL;
704    }
705    foreach_jcr(jcr) {
706       if (strcmp(jcr->Job, Job) == 0) {
707          jcr->inc_use_count();
708          Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", 
709             jcr->JobId, jcr->use_count(), jcr->Job);
710          break;
711       }
712    }
713    endeach_jcr(jcr);
714    return jcr;
715 }
716
717 /* 
718  * Priority runs from 0 (lowest) to 10 (highest)
719  */
720 static int get_status_priority(int JobStatus)
721 {
722    int priority = 0;
723    switch (JobStatus) {
724    case JS_ErrorTerminated:
725    case JS_FatalError:
726       priority = 10;
727       break;
728    case JS_Canceled:
729       priority = 9;
730       break;
731    case JS_Error:
732       priority = 8;
733       break;
734    case JS_Differences:
735       priority = 7;
736       break;
737    }
738    return priority;
739 }
740
741
742 static void update_wait_time(JCR *jcr, int newJobStatus)
743 {
744    bool enter_in_waittime;
745    int oldJobStatus = jcr->JobStatus;
746
747    switch (newJobStatus) {
748    case JS_WaitFD:
749    case JS_WaitSD:
750    case JS_WaitMedia:
751    case JS_WaitMount:
752    case JS_WaitStoreRes:
753    case JS_WaitJobRes:
754    case JS_WaitClientRes:
755    case JS_WaitMaxJobs:
756    case JS_WaitPriority:
757       enter_in_waittime = true;
758       break;
759    default:
760       enter_in_waittime = false; /* not a Wait situation */
761       break;
762    }
763    
764    /*
765     * If we were previously waiting and are not any more
766     *   we want to update the wait_time variable, which is
767     *   the start of waiting.
768     */
769    switch (oldJobStatus) {
770    case JS_WaitFD:
771    case JS_WaitSD:
772    case JS_WaitMedia:
773    case JS_WaitMount:
774    case JS_WaitStoreRes:
775    case JS_WaitJobRes:
776    case JS_WaitClientRes:
777    case JS_WaitMaxJobs:
778    case JS_WaitPriority:
779       if (!enter_in_waittime) { /* we get out the wait time */
780          jcr->wait_time_sum += (time(NULL) - jcr->wait_time);
781          jcr->wait_time = 0;
782       }
783       break;
784
785    /* if wait state is new, we keep current time for watchdog MaxWaitTime */
786    default:
787       if (enter_in_waittime) {
788          jcr->wait_time = time(NULL);
789       }
790       break;
791    }
792 }
793
794 void set_jcr_job_status(JCR *jcr, int JobStatus)
795 {
796    int priority, old_priority;
797    int oldJobStatus = jcr->JobStatus;
798    priority = get_status_priority(JobStatus);
799    old_priority = get_status_priority(oldJobStatus);
800    
801    Dmsg2(800, "set_jcr_job_status(%s, %c)\n", jcr->Job, JobStatus);
802
803    /* Update wait_time depending on newJobStatus and oldJobStatus */
804    update_wait_time(jcr, JobStatus);
805
806    /*
807     * For a set of errors, ... keep the current status
808     *   so it isn't lost. For all others, set it.
809     */
810    Dmsg3(300, "jid=%u OnEntry JobStatus=%c set=%c\n", (uint32_t)jcr->JobId,
811          jcr->JobStatus, JobStatus);
812    if (priority >= old_priority) {
813       jcr->JobStatus = JobStatus;     /* replace with new priority */
814    }
815
816    if (oldJobStatus != jcr->JobStatus) {
817       Dmsg3(200, "jid=%u leave set_old_job_status=%c new_set=%c\n", (uint32_t)jcr->JobId,
818          oldJobStatus, JobStatus);
819 //    generate_plugin_event(jcr, bEventStatusChange, NULL);
820    }
821 }
822
823 #ifdef TRACE_JCR_CHAIN
824 static int lock_count = 0;
825 #endif
826
827 /*
828  * Lock the chain
829  */
830 #ifdef TRACE_JCR_CHAIN
831 static void b_lock_jcr_chain(const char *fname, int line)
832 #else
833 static void lock_jcr_chain()
834 #endif
835 {
836 #ifdef TRACE_JCR_CHAIN
837    Dmsg3(dbglvl, "Lock jcr chain %d from %s:%d\n", ++lock_count, fname, line);
838 #endif
839    P(jcr_lock);
840 }
841
842 /*
843  * Unlock the chain
844  */
845 #ifdef TRACE_JCR_CHAIN
846 static void b_unlock_jcr_chain(const char *fname, int line)
847 #else
848 static void unlock_jcr_chain()
849 #endif
850 {
851 #ifdef TRACE_JCR_CHAIN
852    Dmsg3(dbglvl, "Unlock jcr chain %d from %s:%d\n", lock_count--, fname, line);
853 #endif
854    V(jcr_lock);
855 }
856
857 /*
858  * Start walk of jcr chain
859  * The proper way to walk the jcr chain is:
860  *    JCR *jcr;
861  *    foreach_jcr(jcr) {
862  *      ...
863  *    }
864  *    endeach_jcr(jcr);
865  *
866  *  It is possible to leave out the endeach_jcr(jcr), but
867  *   in that case, the last jcr referenced must be explicitly
868  *   released with:
869  *
870  *    free_jcr(jcr);
871  *  
872  */
873 JCR *jcr_walk_start() 
874 {
875    JCR *jcr;
876    lock_jcr_chain();
877    jcr = (JCR *)jcrs->first();
878    if (jcr) {
879       jcr->inc_use_count();
880       if (jcr->JobId > 0) {
881          Dmsg3(dbglvl, "Inc walk_start jid=%u use_count=%d Job=%s\n", 
882             jcr->JobId, jcr->use_count(), jcr->Job);
883       }
884    }
885    unlock_jcr_chain();
886    return jcr;
887 }
888
889 /*
890  * Get next jcr from chain, and release current one
891  */
892 JCR *jcr_walk_next(JCR *prev_jcr)
893 {
894    JCR *jcr;
895
896    lock_jcr_chain();
897    jcr = (JCR *)jcrs->next(prev_jcr);
898    if (jcr) {
899       jcr->inc_use_count();
900       if (jcr->JobId > 0) {
901          Dmsg3(dbglvl, "Inc walk_next jid=%u use_count=%d Job=%s\n", 
902             jcr->JobId, jcr->use_count(), jcr->Job);
903       }
904    }
905    unlock_jcr_chain();
906    if (prev_jcr) {
907       free_jcr(prev_jcr);
908    }
909    return jcr;
910 }
911
912 /*
913  * Release last jcr referenced
914  */
915 void jcr_walk_end(JCR *jcr)
916 {
917    if (jcr) {
918       if (jcr->JobId > 0) {
919          Dmsg3(dbglvl, "Free walk_end jid=%u use_count=%d Job=%s\n", 
920             jcr->JobId, jcr->use_count(), jcr->Job);
921       }
922       free_jcr(jcr);
923    }
924 }
925
926
927 /*
928  * Setup to call the timeout check routine every 30 seconds
929  *  This routine will check any timers that have been enabled.
930  */
931 bool init_jcr_subsystem(void)
932 {
933    watchdog_t *wd = new_watchdog();
934
935    wd->one_shot = false;
936    wd->interval = 30;   /* FIXME: should be configurable somewhere, even
937                          if only with a #define */
938    wd->callback = jcr_timeout_check;
939
940    register_watchdog(wd);
941
942    return true;
943 }
944
945 static void jcr_timeout_check(watchdog_t *self)
946 {
947    JCR *jcr;
948    BSOCK *bs;
949    time_t timer_start;
950
951    Dmsg0(dbglvl, "Start JCR timeout checks\n");
952
953    /* Walk through all JCRs checking if any one is
954     * blocked for more than specified max time.
955     */
956    foreach_jcr(jcr) {
957       Dmsg2(dbglvl, "jcr_timeout_check JobId=%u jcr=0x%x\n", jcr->JobId, jcr);
958       if (jcr->JobId == 0) {
959          continue;
960       }
961       bs = jcr->store_bsock;
962       if (bs) {
963          timer_start = bs->timer_start;
964          if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
965             bs->timer_start = 0;      /* turn off timer */
966             bs->set_timed_out();
967             Qmsg(jcr, M_ERROR, 0, _(
968 "Watchdog sending kill after %d secs to thread stalled reading Storage daemon.\n"),
969                  watchdog_time - timer_start);
970             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
971          }
972       }
973       bs = jcr->file_bsock;
974       if (bs) {
975          timer_start = bs->timer_start;
976          if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
977             bs->timer_start = 0;      /* turn off timer */
978             bs->set_timed_out();
979             Qmsg(jcr, M_ERROR, 0, _(
980 "Watchdog sending kill after %d secs to thread stalled reading File daemon.\n"),
981                  watchdog_time - timer_start);
982             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
983          }
984       }
985       bs = jcr->dir_bsock;
986       if (bs) {
987          timer_start = bs->timer_start;
988          if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
989             bs->timer_start = 0;      /* turn off timer */
990             bs->set_timed_out();
991             Qmsg(jcr, M_ERROR, 0, _(
992 "Watchdog sending kill after %d secs to thread stalled reading Director.\n"),
993                  watchdog_time - timer_start);
994             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
995          }
996       }
997    }
998    endeach_jcr(jcr);
999
1000    Dmsg0(dbglvl, "Finished JCR timeout checks\n");
1001 }
1002
1003 /*
1004  * Timeout signal comes here
1005  */
1006 extern "C" void timeout_handler(int sig)
1007 {
1008    return;                            /* thus interrupting the function */
1009 }
1010
1011 /* Used to display specific daemon information after a fatal signal 
1012  * (like B_DB in the director)
1013  */
1014 #define MAX_DBG_HOOK 10
1015 static dbg_jcr_hook_t *dbg_jcr_hooks[MAX_DBG_HOOK];
1016 static int dbg_jcr_handler_count;
1017
1018 void dbg_jcr_add_hook(dbg_jcr_hook_t *fct)
1019 {
1020    ASSERT(dbg_jcr_handler_count < MAX_DBG_HOOK);
1021    dbg_jcr_hooks[dbg_jcr_handler_count++] = fct;
1022 }
1023
1024 /*
1025  * !!! WARNING !!! 
1026  *
1027  * This function should be used ONLY after a fatal signal. We walk through the
1028  * JCR chain without doing any lock, bacula should not be running.
1029  */
1030 void _dbg_print_jcr(FILE *fp)
1031 {
1032    char buf1[128], buf2[128], buf3[128], buf4[128];
1033    if (!jcrs) {
1034       return;
1035    }
1036
1037    fprintf(fp, "Attempt to dump current JCRs\n");
1038
1039    for (JCR *jcr = (JCR *)jcrs->first(); jcr ; jcr = (JCR *)jcrs->next(jcr)) {
1040       if (!jcr) {               /* protect us against something ? */
1041          continue;
1042       }
1043       
1044       fprintf(fp, "JCR=%p JobId=%i name=%s JobStatus=%c\n", 
1045               jcr, jcr->JobId, jcr->Job, jcr->JobStatus);
1046 #ifdef HAVE_WIN32
1047       fprintf(fp, "\tuse_count=%i\n",
1048               jcr->use_count());
1049 #else
1050       fprintf(fp, "\tuse_count=%i threadid=0x%x\n",
1051               jcr->use_count(), (int)jcr->my_thread_id);
1052 #endif
1053       fprintf(fp, "\tJobType=%c JobLevel=%c\n",
1054               jcr->get_JobType(), jcr->get_JobLevel());
1055       bstrftime(buf1, sizeof(buf1), jcr->sched_time);
1056       bstrftime(buf2, sizeof(buf2), jcr->start_time);
1057       bstrftime(buf3, sizeof(buf3), jcr->end_time);
1058       bstrftime(buf4, sizeof(buf4), jcr->wait_time);
1059       fprintf(fp, "\tsched_time=%s start_time=%s\n\tend_time=%s wait_time=%s\n",
1060               buf1, buf2, buf3, buf4);
1061       fprintf(fp, "\tdequeing=%i\n", jcr->dequeuing);
1062       fprintf(fp, "\tdb=%p db_batch=%p batch_started=%i\n", 
1063               jcr->db, jcr->db_batch, jcr->batch_started);
1064       
1065       for(int i=0; i < dbg_jcr_handler_count; i++) {
1066          dbg_jcr_hook_t *fct = dbg_jcr_hooks[i];
1067          fct(jcr, fp);
1068       }
1069    }
1070 }
1071