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