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