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