]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/jcr.c
Add comment
[bacula/bacula] / bacula / src / lib / jcr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 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 bool JCR::JobReads()
274 {
275    switch (m_JobType) {
276    case JT_VERIFY:
277    case JT_RESTORE:
278    case JT_COPY:
279    case JT_MIGRATE:
280       return true;
281    case JT_BACKUP:
282       if (m_JobLevel == L_VIRTUAL_FULL) {
283          return true;
284       }
285       break;
286    default:
287       break;
288    }
289    return false;
290 }
291
292 /*
293  * Push a subroutine address into the job end callback stack
294  */
295 void job_end_push(JCR *jcr, void job_end_cb(JCR *jcr,void *), void *ctx)
296 {
297    jcr->job_end_push.append((void *)job_end_cb);
298    jcr->job_end_push.append(ctx);
299 }
300
301 /* Pop each job_end subroutine and call it */
302 static void job_end_pop(JCR *jcr)
303 {
304    void (*job_end_cb)(JCR *jcr, void *ctx);
305    void *ctx;
306    for (int i=jcr->job_end_push.size()-1; i > 0; ) {
307       ctx = jcr->job_end_push.get(i--);
308       job_end_cb = (void (*)(JCR *,void *))jcr->job_end_push.get(i--);
309       job_end_cb(jcr, ctx);
310    }
311 }
312
313 #
314 # Create thread key for thread specific data
315 #
316 void create_jcr_key()
317 {
318    int status = pthread_key_create(&jcr_key, NULL);
319    if (status != 0) {
320       berrno be;
321       Jmsg1(NULL, M_ABORT, 0, _("pthread key create failed: ERR=%s\n"),
322             be.bstrerror(status));
323    }
324 }
325
326 /*
327  * Create a Job Control Record and link it into JCR chain
328  * Returns newly allocated JCR
329  * Note, since each daemon has a different JCR, he passes
330  *  us the size.
331  */
332 JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr)
333 {
334    JCR *jcr;
335    MQUEUE_ITEM *item = NULL;
336    struct sigaction sigtimer;
337    int status;
338
339    Dmsg0(dbglvl, "Enter new_jcr\n");
340    status = pthread_once(&key_once, create_jcr_key);
341    if (status != 0) {
342       berrno be;
343       Jmsg1(NULL, M_ABORT, 0, _("pthread_once failed. ERR=%s\n"), be.bstrerror(status));
344    }
345    jcr = (JCR *)malloc(size);
346    memset(jcr, 0, size);
347    jcr->my_thread_id = pthread_self();
348    jcr->msg_queue = New(dlist(item, &item->link));
349    jcr->job_end_push.init(1, false);
350    jcr->sched_time = time(NULL);
351    jcr->daemon_free_jcr = daemon_free_jcr;    /* plug daemon free routine */
352    jcr->init_mutex();
353    jcr->inc_use_count();   
354    jcr->VolumeName = get_pool_memory(PM_FNAME);
355    jcr->VolumeName[0] = 0;
356    jcr->errmsg = get_pool_memory(PM_MESSAGE);
357    jcr->errmsg[0] = 0;
358    /* Setup some dummy values */
359    bstrncpy(jcr->Job, "*System*", sizeof(jcr->Job));
360    jcr->JobId = 0;
361    jcr->setJobType(JT_SYSTEM);           /* internal job until defined */
362    jcr->setJobLevel(L_NONE);
363    jcr->setJobStatus(JS_Created);        /* ready to run */
364    set_jcr_in_tsd(jcr);
365    sigtimer.sa_flags = 0;
366    sigtimer.sa_handler = timeout_handler;
367    sigfillset(&sigtimer.sa_mask);
368    sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL);
369
370    /*
371     * Locking jobs is a global lock that is needed
372     * so that the Director can stop new jobs from being
373     * added to the jcr chain while it processes a new
374     * conf file and does the job_end_push().
375     */
376    lock_jobs();
377    lock_jcr_chain();
378    if (!jcrs) {
379       jcrs = New(dlist(jcr, &jcr->link));
380    }
381    jcrs->append(jcr);
382    unlock_jcr_chain();
383    unlock_jobs();
384
385    return jcr;
386 }
387
388
389 /*
390  * Remove a JCR from the chain
391  * NOTE! The chain must be locked prior to calling
392  *       this routine.
393  */
394 static void remove_jcr(JCR *jcr)
395 {
396    Dmsg0(dbglvl, "Enter remove_jcr\n");
397    if (!jcr) {
398       Emsg0(M_ABORT, 0, _("NULL jcr.\n"));
399    }
400    jcrs->remove(jcr);
401    Dmsg0(dbglvl, "Leave remove_jcr\n");
402 }
403
404 /*
405  * Free stuff common to all JCRs.  N.B. Be careful to include only
406  *  generic stuff in the common part of the jcr.
407  */
408 static void free_common_jcr(JCR *jcr)
409 {
410    jcr->destroy_mutex();
411
412    if (jcr->msg_queue) {
413       delete jcr->msg_queue;
414       jcr->msg_queue = NULL;
415    }
416    close_msg(jcr);                    /* close messages for this job */
417
418    /* do this after closing messages */
419    if (jcr->client_name) {
420       free_pool_memory(jcr->client_name);
421       jcr->client_name = NULL;
422    }
423
424    if (jcr->attr) {
425       free_pool_memory(jcr->attr);
426       jcr->attr = NULL;
427    }
428
429    if (jcr->sd_auth_key) {
430       free(jcr->sd_auth_key);
431       jcr->sd_auth_key = NULL;
432    }
433    if (jcr->VolumeName) {
434       free_pool_memory(jcr->VolumeName);
435       jcr->VolumeName = NULL;
436    }
437
438    if (jcr->dir_bsock) {
439       bnet_close(jcr->dir_bsock);
440       jcr->dir_bsock = NULL;
441    }
442    if (jcr->errmsg) {
443       free_pool_memory(jcr->errmsg);
444       jcr->errmsg = NULL;
445    }
446    if (jcr->where) {
447       free(jcr->where);
448       jcr->where = NULL;
449    }
450    if (jcr->RegexWhere) {
451       free(jcr->RegexWhere);
452       jcr->RegexWhere = NULL;
453    }
454    if (jcr->where_bregexp) {
455       free_bregexps(jcr->where_bregexp);
456       delete jcr->where_bregexp;
457       jcr->where_bregexp = NULL;
458    }
459    if (jcr->cached_path) {
460       free_pool_memory(jcr->cached_path);
461       jcr->cached_path = NULL;
462       jcr->cached_pnl = 0;
463    }
464    if (jcr->id_list) {
465       free_guid_list(jcr->id_list);
466       jcr->id_list = NULL;
467    }
468    remove_jcr_from_tsd(jcr);
469    free(jcr);
470 }
471
472 /*
473  * Global routine to free a jcr
474  */
475 #ifdef DEBUG
476 void b_free_jcr(const char *file, int line, JCR *jcr)
477 {
478    struct s_last_job *je;
479
480    Dmsg3(dbglvl, "Enter free_jcr jid=%u from %s:%d\n", jcr->JobId, file, line);
481
482 #else
483
484 void free_jcr(JCR *jcr)
485 {
486    struct s_last_job *je;
487
488    Dmsg3(dbglvl, "Enter free_jcr jid=%u use_count=%d Job=%s\n", 
489          jcr->JobId, jcr->use_count(), jcr->Job);
490
491 #endif
492
493    lock_jcr_chain();
494    jcr->dec_use_count();              /* decrement use count */
495    if (jcr->use_count() < 0) {
496       Jmsg2(jcr, M_ERROR, 0, _("JCR use_count=%d JobId=%d\n"),
497          jcr->use_count(), jcr->JobId);
498    }
499    if (jcr->JobId > 0) {
500       Dmsg3(dbglvl, "Dec free_jcr jid=%u use_count=%d Job=%s\n", 
501          jcr->JobId, jcr->use_count(), jcr->Job);
502    }
503    if (jcr->use_count() > 0) {          /* if in use */
504       unlock_jcr_chain();
505       return;
506    }
507    if (jcr->JobId > 0) {
508       Dmsg3(dbglvl, "remove jcr jid=%u use_count=%d Job=%s\n", 
509             jcr->JobId, jcr->use_count(), jcr->Job);
510    }
511    remove_jcr(jcr);                   /* remove Jcr from chain */
512    unlock_jcr_chain();
513
514    dequeue_messages(jcr);
515    job_end_pop(jcr);                  /* pop and call hooked routines */
516
517    Dmsg1(dbglvl, "End job=%d\n", jcr->JobId);
518
519    /* Keep some statistics */
520    switch (jcr->get_JobType()) {
521    case JT_BACKUP:
522    case JT_VERIFY:
523    case JT_RESTORE:
524    case JT_MIGRATE:
525    case JT_COPY:
526    case JT_ADMIN:
527       /* Keep list of last jobs, but not Console where JobId==0 */
528       if (jcr->JobId > 0) {
529          lock_last_jobs_list();
530          num_jobs_run++;
531          je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
532          memset(je, 0, sizeof(struct s_last_job));  /* zero in case unset fields */
533          je->Errors = jcr->JobErrors;
534          je->JobType = jcr->get_JobType();
535          je->JobId = jcr->JobId;
536          je->VolSessionId = jcr->VolSessionId;
537          je->VolSessionTime = jcr->VolSessionTime;
538          bstrncpy(je->Job, jcr->Job, sizeof(je->Job));
539          je->JobFiles = jcr->JobFiles;
540          je->JobBytes = jcr->JobBytes;
541          je->JobStatus = jcr->JobStatus;
542          je->JobLevel = jcr->get_JobLevel();
543          je->start_time = jcr->start_time;
544          je->end_time = time(NULL);
545
546          if (!last_jobs) {
547             init_last_jobs_list();
548          }
549          last_jobs->append(je);
550          if (last_jobs->size() > max_last_jobs) {
551             je = (struct s_last_job *)last_jobs->first();
552             last_jobs->remove(je);
553             free(je);
554          }
555          unlock_last_jobs_list();
556       }
557       break;
558    default:
559       break;
560    }
561
562    if (jcr->daemon_free_jcr) {
563       jcr->daemon_free_jcr(jcr);      /* call daemon free routine */
564    }
565
566    free_common_jcr(jcr);
567    close_msg(NULL);                   /* flush any daemon messages */
568    garbage_collect_memory_pool();
569    Dmsg0(dbglvl, "Exit free_jcr\n");
570 }
571
572 /*
573  * Remove jcr from thread specific data, but
574  *   but make sure it is us who are attached.
575  */
576 void remove_jcr_from_tsd(JCR *jcr)
577 {
578    JCR *tjcr = get_jcr_from_tsd();
579    if (tjcr == jcr) { 
580       set_jcr_in_tsd(INVALID_JCR);
581    }
582 }
583
584 /*
585  * Put this jcr in the thread specifc data 
586  */
587 void set_jcr_in_tsd(JCR *jcr)
588 {
589    int status = pthread_setspecific(jcr_key, (void *)jcr);
590    if (status != 0) {
591       berrno be;
592       Jmsg1(jcr, M_ABORT, 0, _("pthread_setspecific failed: ERR=%s\n"), be.bstrerror(status));
593    }
594 }
595
596 /*
597  * Give me the jcr that is attached to this thread
598  */
599 JCR *get_jcr_from_tsd()
600 {
601    JCR *jcr = (JCR *)pthread_getspecific(jcr_key);
602 // printf("get_jcr_from_tsd: jcr=%p\n", jcr);
603    /* set any INVALID_JCR to NULL which the rest of Bacula understands */
604    if (jcr == INVALID_JCR) {
605       jcr = NULL;
606    }
607    return jcr;
608 }
609
610  
611 /*
612  * Find which JobId corresponds to the current thread
613  */
614 uint32_t get_jobid_from_tsd()
615 {
616    JCR *jcr;
617    uint32_t JobId = 0;
618    jcr = get_jcr_from_tsd();
619 // printf("get_jobid_from_tsr: jcr=%p\n", jcr);
620    if (jcr) {
621       JobId = (uint32_t)jcr->JobId;
622    }
623    return JobId;
624 }
625
626 /*
627  * Given a JobId, find the JCR
628  *   Returns: jcr on success
629  *            NULL on failure
630  */
631 JCR *get_jcr_by_id(uint32_t JobId)
632 {
633    JCR *jcr;
634
635    foreach_jcr(jcr) {
636       if (jcr->JobId == JobId) {
637          jcr->inc_use_count();
638          Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", 
639             jcr->JobId, jcr->use_count(), jcr->Job);
640          break;
641       }
642    }
643    endeach_jcr(jcr);
644    return jcr;
645 }
646
647 /*
648  * Given a thread id, find the JobId
649  *   Returns: JobId on success
650  *            0 on failure
651  */
652 uint32_t get_jobid_from_tid(pthread_t tid)
653 {
654    JCR *jcr = NULL;
655    bool found = false;
656
657    foreach_jcr(jcr) {
658       if (pthread_equal(jcr->my_thread_id, tid)) {
659          found = true;
660          break;
661       }
662    }
663    endeach_jcr(jcr);
664    if (found) {
665       return jcr->JobId;
666    }
667    return 0;
668 }
669
670
671 /*
672  * Given a SessionId and SessionTime, find the JCR
673  *   Returns: jcr on success
674  *            NULL on failure
675  */
676 JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime)
677 {
678    JCR *jcr;
679
680    foreach_jcr(jcr) {
681       if (jcr->VolSessionId == SessionId &&
682           jcr->VolSessionTime == SessionTime) {
683          jcr->inc_use_count();
684          Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", 
685             jcr->JobId, jcr->use_count(), jcr->Job);
686          break;
687       }
688    }
689    endeach_jcr(jcr);
690    return jcr;
691 }
692
693
694 /*
695  * Given a Job, find the JCR
696  *  compares on the number of characters in Job
697  *  thus allowing partial matches.
698  *   Returns: jcr on success
699  *            NULL on failure
700  */
701 JCR *get_jcr_by_partial_name(char *Job)
702 {
703    JCR *jcr;
704    int len;
705
706    if (!Job) {
707       return NULL;
708    }
709    len = strlen(Job);
710    foreach_jcr(jcr) {
711       if (strncmp(Job, jcr->Job, len) == 0) {
712          jcr->inc_use_count();
713          Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", 
714             jcr->JobId, jcr->use_count(), jcr->Job);
715          break;
716       }
717    }
718    endeach_jcr(jcr);
719    return jcr;
720 }
721
722
723 /*
724  * Given a Job, find the JCR
725  *  requires an exact match of names.
726  *   Returns: jcr on success
727  *            NULL on failure
728  */
729 JCR *get_jcr_by_full_name(char *Job)
730 {
731    JCR *jcr;
732
733    if (!Job) {
734       return NULL;
735    }
736    foreach_jcr(jcr) {
737       if (strcmp(jcr->Job, Job) == 0) {
738          jcr->inc_use_count();
739          Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", 
740             jcr->JobId, jcr->use_count(), jcr->Job);
741          break;
742       }
743    }
744    endeach_jcr(jcr);
745    return jcr;
746 }
747
748 /* 
749  * Priority runs from 0 (lowest) to 10 (highest)
750  */
751 static int get_status_priority(int JobStatus)
752 {
753    int priority = 0;
754    switch (JobStatus) {
755    case JS_ErrorTerminated:
756    case JS_FatalError:
757    case JS_Canceled:
758    case JS_Incomplete:
759       priority = 10;
760       break;
761    case JS_Error:
762       priority = 8;
763       break;
764    case JS_Differences:
765       priority = 7;
766       break;
767    }
768    return priority;
769 }
770
771
772 static void update_wait_time(JCR *jcr, int newJobStatus)
773 {
774    bool enter_in_waittime;
775    int oldJobStatus = jcr->JobStatus;
776
777    switch (newJobStatus) {
778    case JS_WaitFD:
779    case JS_WaitSD:
780    case JS_WaitMedia:
781    case JS_WaitMount:
782    case JS_WaitStoreRes:
783    case JS_WaitJobRes:
784    case JS_WaitClientRes:
785    case JS_WaitMaxJobs:
786    case JS_WaitPriority:
787       enter_in_waittime = true;
788       break;
789    default:
790       enter_in_waittime = false; /* not a Wait situation */
791       break;
792    }
793    
794    /*
795     * If we were previously waiting and are not any more
796     *   we want to update the wait_time variable, which is
797     *   the start of waiting.
798     */
799    switch (oldJobStatus) {
800    case JS_WaitFD:
801    case JS_WaitSD:
802    case JS_WaitMedia:
803    case JS_WaitMount:
804    case JS_WaitStoreRes:
805    case JS_WaitJobRes:
806    case JS_WaitClientRes:
807    case JS_WaitMaxJobs:
808    case JS_WaitPriority:
809       if (!enter_in_waittime) { /* we get out the wait time */
810          jcr->wait_time_sum += (time(NULL) - jcr->wait_time);
811          jcr->wait_time = 0;
812       }
813       break;
814
815    /* if wait state is new, we keep current time for watchdog MaxWaitTime */
816    default:
817       if (enter_in_waittime) {
818          jcr->wait_time = time(NULL);
819       }
820       break;
821    }
822 }
823
824 void set_jcr_job_status(JCR *jcr, int JobStatus)
825 {
826    jcr->setJobStatus(JobStatus);
827 }
828
829 void JCR::setJobStatus(int JobStatus)
830 {
831    JCR *jcr = this;
832    int priority, old_priority;
833    int oldJobStatus = JobStatus;
834    priority = get_status_priority(JobStatus);
835    old_priority = get_status_priority(oldJobStatus);
836    
837    Dmsg2(800, "set_jcr_job_status(%s, %c)\n", Job, JobStatus);
838
839    /* Update wait_time depending on newJobStatus and oldJobStatus */
840    update_wait_time(this, JobStatus);
841
842    /*
843     * For a set of errors, ... keep the current status
844     *   so it isn't lost. For all others, set it.
845     */
846    Dmsg3(300, "jid=%u OnEntry JobStatus=%c set=%c\n", (uint32_t)JobId,
847          JobStatus, JobStatus);
848    if (priority >= old_priority) {
849       jcr->JobStatus = JobStatus;     /* replace with new priority */
850    }
851
852    if (oldJobStatus != jcr->JobStatus) {
853       Dmsg3(200, "jid=%u leave set_old_job_status=%c new_set=%c\n", (uint32_t)jcr->JobId,
854          oldJobStatus, JobStatus);
855 //    generate_plugin_event(jcr, bEventStatusChange, NULL);
856    }
857 }
858
859 #ifdef TRACE_JCR_CHAIN
860 static int lock_count = 0;
861 #endif
862
863 /*
864  * Lock the chain
865  */
866 #ifdef TRACE_JCR_CHAIN
867 static void b_lock_jcr_chain(const char *fname, int line)
868 #else
869 static void lock_jcr_chain()
870 #endif
871 {
872 #ifdef TRACE_JCR_CHAIN
873    Dmsg3(dbglvl, "Lock jcr chain %d from %s:%d\n", ++lock_count, fname, line);
874 #endif
875    P(jcr_lock);
876 }
877
878 /*
879  * Unlock the chain
880  */
881 #ifdef TRACE_JCR_CHAIN
882 static void b_unlock_jcr_chain(const char *fname, int line)
883 #else
884 static void unlock_jcr_chain()
885 #endif
886 {
887 #ifdef TRACE_JCR_CHAIN
888    Dmsg3(dbglvl, "Unlock jcr chain %d from %s:%d\n", lock_count--, fname, line);
889 #endif
890    V(jcr_lock);
891 }
892
893 /*
894  * Start walk of jcr chain
895  * The proper way to walk the jcr chain is:
896  *    JCR *jcr;
897  *    foreach_jcr(jcr) {
898  *      ...
899  *    }
900  *    endeach_jcr(jcr);
901  *
902  *  It is possible to leave out the endeach_jcr(jcr), but
903  *   in that case, the last jcr referenced must be explicitly
904  *   released with:
905  *
906  *    free_jcr(jcr);
907  *  
908  */
909 JCR *jcr_walk_start() 
910 {
911    JCR *jcr;
912    lock_jcr_chain();
913    jcr = (JCR *)jcrs->first();
914    if (jcr) {
915       jcr->inc_use_count();
916       if (jcr->JobId > 0) {
917          Dmsg3(dbglvl, "Inc walk_start jid=%u use_count=%d Job=%s\n", 
918             jcr->JobId, jcr->use_count(), jcr->Job);
919       }
920    }
921    unlock_jcr_chain();
922    return jcr;
923 }
924
925 /*
926  * Get next jcr from chain, and release current one
927  */
928 JCR *jcr_walk_next(JCR *prev_jcr)
929 {
930    JCR *jcr;
931
932    lock_jcr_chain();
933    jcr = (JCR *)jcrs->next(prev_jcr);
934    if (jcr) {
935       jcr->inc_use_count();
936       if (jcr->JobId > 0) {
937          Dmsg3(dbglvl, "Inc walk_next jid=%u use_count=%d Job=%s\n", 
938             jcr->JobId, jcr->use_count(), jcr->Job);
939       }
940    }
941    unlock_jcr_chain();
942    if (prev_jcr) {
943       free_jcr(prev_jcr);
944    }
945    return jcr;
946 }
947
948 /*
949  * Release last jcr referenced
950  */
951 void jcr_walk_end(JCR *jcr)
952 {
953    if (jcr) {
954       if (jcr->JobId > 0) {
955          Dmsg3(dbglvl, "Free walk_end jid=%u use_count=%d Job=%s\n", 
956             jcr->JobId, jcr->use_count(), jcr->Job);
957       }
958       free_jcr(jcr);
959    }
960 }
961
962
963 /*
964  * Setup to call the timeout check routine every 30 seconds
965  *  This routine will check any timers that have been enabled.
966  */
967 bool init_jcr_subsystem(void)
968 {
969    watchdog_t *wd = new_watchdog();
970
971    wd->one_shot = false;
972    wd->interval = 30;   /* FIXME: should be configurable somewhere, even
973                          if only with a #define */
974    wd->callback = jcr_timeout_check;
975
976    register_watchdog(wd);
977
978    return true;
979 }
980
981 static void jcr_timeout_check(watchdog_t *self)
982 {
983    JCR *jcr;
984    BSOCK *bs;
985    time_t timer_start;
986
987    Dmsg0(dbglvl, "Start JCR timeout checks\n");
988
989    /* Walk through all JCRs checking if any one is
990     * blocked for more than specified max time.
991     */
992    foreach_jcr(jcr) {
993       Dmsg2(dbglvl, "jcr_timeout_check JobId=%u jcr=0x%x\n", jcr->JobId, jcr);
994       if (jcr->JobId == 0) {
995          continue;
996       }
997       bs = jcr->store_bsock;
998       if (bs) {
999          timer_start = bs->timer_start;
1000          if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
1001             bs->timer_start = 0;      /* turn off timer */
1002             bs->set_timed_out();
1003             Qmsg(jcr, M_ERROR, 0, _(
1004 "Watchdog sending kill after %d secs to thread stalled reading Storage daemon.\n"),
1005                  watchdog_time - timer_start);
1006             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
1007          }
1008       }
1009       bs = jcr->file_bsock;
1010       if (bs) {
1011          timer_start = bs->timer_start;
1012          if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
1013             bs->timer_start = 0;      /* turn off timer */
1014             bs->set_timed_out();
1015             Qmsg(jcr, M_ERROR, 0, _(
1016 "Watchdog sending kill after %d secs to thread stalled reading File daemon.\n"),
1017                  watchdog_time - timer_start);
1018             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
1019          }
1020       }
1021       bs = jcr->dir_bsock;
1022       if (bs) {
1023          timer_start = bs->timer_start;
1024          if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
1025             bs->timer_start = 0;      /* turn off timer */
1026             bs->set_timed_out();
1027             Qmsg(jcr, M_ERROR, 0, _(
1028 "Watchdog sending kill after %d secs to thread stalled reading Director.\n"),
1029                  watchdog_time - timer_start);
1030             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
1031          }
1032       }
1033    }
1034    endeach_jcr(jcr);
1035
1036    Dmsg0(dbglvl, "Finished JCR timeout checks\n");
1037 }
1038
1039 /* 
1040  * Return next JobId from comma separated list   
1041  *
1042  * Returns:
1043  *   1 if next JobId returned
1044  *   0 if no more JobIds are in list
1045  *  -1 there is an error
1046  */
1047 int get_next_jobid_from_list(char **p, uint32_t *JobId)
1048 {
1049    const int maxlen = 30;
1050    char jobid[maxlen+1];
1051    char *q = *p;
1052
1053    jobid[0] = 0;
1054    for (int i=0; i<maxlen; i++) {
1055       if (*q == 0) {
1056          break;
1057       } else if (*q == ',') {
1058          q++;
1059          break;
1060       }
1061       jobid[i] = *q++;
1062       jobid[i+1] = 0;
1063    }
1064    if (jobid[0] == 0) {
1065       return 0;
1066    } else if (!is_a_number(jobid)) {
1067       return -1;                      /* error */
1068    }
1069    *p = q;
1070    *JobId = str_to_int64(jobid);
1071    return 1;
1072 }
1073
1074 /*
1075  * Timeout signal comes here
1076  */
1077 extern "C" void timeout_handler(int sig)
1078 {
1079    return;                            /* thus interrupting the function */
1080 }
1081
1082 /* Used to display specific daemon information after a fatal signal 
1083  * (like B_DB in the director)
1084  */
1085 #define MAX_DBG_HOOK 10
1086 static dbg_jcr_hook_t *dbg_jcr_hooks[MAX_DBG_HOOK];
1087 static int dbg_jcr_handler_count;
1088
1089 void dbg_jcr_add_hook(dbg_jcr_hook_t *fct)
1090 {
1091    ASSERT(dbg_jcr_handler_count < MAX_DBG_HOOK);
1092    dbg_jcr_hooks[dbg_jcr_handler_count++] = fct;
1093 }
1094
1095 /*
1096  * !!! WARNING !!! 
1097  *
1098  * This function should be used ONLY after a fatal signal. We walk through the
1099  * JCR chain without doing any lock, bacula should not be running.
1100  */
1101 void _dbg_print_jcr(FILE *fp)
1102 {
1103    char buf1[128], buf2[128], buf3[128], buf4[128];
1104    if (!jcrs) {
1105       return;
1106    }
1107
1108    fprintf(fp, "Attempt to dump current JCRs\n");
1109
1110    for (JCR *jcr = (JCR *)jcrs->first(); jcr ; jcr = (JCR *)jcrs->next(jcr)) {
1111       if (!jcr) {               /* protect us against something ? */
1112          continue;
1113       }
1114       
1115       fprintf(fp, "JCR=%p JobId=%i name=%s JobStatus=%c\n", 
1116               jcr, jcr->JobId, jcr->Job, jcr->JobStatus);
1117 #ifdef HAVE_WIN32
1118       fprintf(fp, "\tuse_count=%i\n",
1119               jcr->use_count());
1120 #else
1121       /* KES -- removed non-portable code referencing pthread_t */
1122       fprintf(fp, "\tuse_count=%d\n", jcr->use_count());
1123 #endif
1124       fprintf(fp, "\tJobType=%c JobLevel=%c\n",
1125               jcr->get_JobType(), jcr->get_JobLevel());
1126       bstrftime(buf1, sizeof(buf1), jcr->sched_time);
1127       bstrftime(buf2, sizeof(buf2), jcr->start_time);
1128       bstrftime(buf3, sizeof(buf3), jcr->end_time);
1129       bstrftime(buf4, sizeof(buf4), jcr->wait_time);
1130       fprintf(fp, "\tsched_time=%s start_time=%s\n\tend_time=%s wait_time=%s\n",
1131               buf1, buf2, buf3, buf4);
1132       fprintf(fp, "\tdequeing=%i\n", jcr->dequeuing);
1133       fprintf(fp, "\tdb=%p db_batch=%p batch_started=%i\n", 
1134               jcr->db, jcr->db_batch, jcr->batch_started);
1135       
1136       for(int i=0; i < dbg_jcr_handler_count; i++) {
1137          dbg_jcr_hook_t *fct = dbg_jcr_hooks[i];
1138          fct(jcr, fp);
1139       }
1140    }
1141 }