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