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