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