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