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