]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/jcr.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / lib / jcr.c
1 /*
2  * Manipulation routines for Job Control Records
3  *
4  *  Kern E. Sibbald, December 2000
5  *
6  *  Version $Id$
7  *
8  *  These routines are thread safe.
9  *
10  */
11 /*
12    Copyright (C) 2000-2003 Kern Sibbald and John Walker
13
14    This program is free software; you can redistribute it and/or
15    modify it under the terms of the GNU General Public License as
16    published by the Free Software Foundation; either version 2 of
17    the License, or (at your option) any later version.
18
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22    General Public License for more details.
23
24    You should have received a copy of the GNU General Public
25    License along with this program; if not, write to the Free
26    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27    MA 02111-1307, USA.
28
29  */
30
31 #include "bacula.h"
32 #include "jcr.h"
33
34 extern void timeout_handler(int sig);
35
36 struct s_last_job last_job;    /* last job run by this daemon */
37 dlist *last_jobs;
38 #define MAX_LAST_JOBS 10
39
40 static JCR *jobs = NULL;              /* pointer to JCR chain */
41
42 /* Mutex for locking various jcr chains while updating */
43 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
44
45 void init_last_jobs_list()
46 {
47    struct s_last_job *job_entry;
48    last_jobs = new dlist(job_entry,  &job_entry->link);
49    memset(&last_job, 0, sizeof(last_job));
50 }
51
52 void term_last_jobs_list()
53 {
54    for (void *je=NULL; (je=last_jobs->next(je)); ) {
55       free(je);                     
56    }
57    delete last_jobs;
58 }
59
60 void lock_last_jobs_list() 
61 {
62    P(mutex);
63 }
64
65 void unlock_last_jobs_list() 
66 {
67    V(mutex);
68 }
69
70 /*
71  * Create a Job Control Record and link it into JCR chain
72  * Returns newly allocated JCR
73  * Note, since each daemon has a different JCR, he passes
74  *  us the size.
75  */
76 JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr)
77 {
78    JCR *jcr;
79    struct sigaction sigtimer;
80
81    Dmsg0(200, "Enter new_jcr\n");
82    jcr = (JCR *)malloc(size);
83    memset(jcr, 0, size);
84    jcr->my_thread_id = pthread_self();
85    jcr->sched_time = time(NULL);
86    jcr->daemon_free_jcr = daemon_free_jcr;    /* plug daemon free routine */
87    jcr->use_count = 1;
88    pthread_mutex_init(&(jcr->mutex), NULL);
89    jcr->JobStatus = JS_Created;       /* ready to run */
90    jcr->VolumeName = get_pool_memory(PM_FNAME);
91    jcr->VolumeName[0] = 0;
92    jcr->errmsg = get_pool_memory(PM_MESSAGE);
93    jcr->errmsg[0] = 0;
94    strcpy(jcr->Job, "*Console*");     /* default */
95
96    sigtimer.sa_flags = 0;
97    sigtimer.sa_handler = timeout_handler;
98    sigfillset(&sigtimer.sa_mask);
99    sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL);
100
101    P(mutex);
102    jcr->prev = NULL;
103    jcr->next = jobs;
104    if (jobs) {
105       jobs->prev = jcr;
106    }
107    jobs = jcr;
108    V(mutex);
109    return jcr;
110 }
111
112
113 /*
114  * Remove a JCR from the chain
115  * NOTE! The chain must be locked prior to calling
116  *       this routine.
117  */
118 static void remove_jcr(JCR *jcr)
119 {
120    Dmsg0(150, "Enter remove_jcr\n");
121    if (!jcr) {
122       Emsg0(M_ABORT, 0, "NULL jcr.\n");
123    }
124    if (!jcr->prev) {                  /* if no prev */
125       jobs = jcr->next;               /* set new head */
126    } else {
127       jcr->prev->next = jcr->next;    /* update prev */
128    }
129    if (jcr->next) {
130       jcr->next->prev = jcr->prev;
131    }
132    Dmsg0(150, "Leave remove_jcr\n");
133 }
134
135 /*
136  * Free stuff common to all JCRs.  N.B. Be careful to include only
137  *  generic stuff in the common part of the jcr. 
138  */
139 static void free_common_jcr(JCR *jcr)
140 {
141    /* Keep some statistics */
142    switch (jcr->JobType) {
143    case JT_BACKUP:
144    case JT_VERIFY:
145    case JT_RESTORE:
146    case JT_ADMIN:
147       last_job.NumJobs++;
148       last_job.JobType = jcr->JobType;
149       last_job.JobId = jcr->JobId;
150       last_job.VolSessionId = jcr->VolSessionId;
151       last_job.VolSessionTime = jcr->VolSessionTime;
152       bstrncpy(last_job.Job, jcr->Job, sizeof(last_job.Job));
153       last_job.JobFiles = jcr->JobFiles;
154       last_job.JobBytes = jcr->JobBytes;
155       last_job.JobStatus = jcr->JobStatus;
156       last_job.JobLevel = jcr->JobLevel;
157       last_job.start_time = jcr->start_time;
158       last_job.end_time = time(NULL);
159       break;
160    default:
161       break;
162    }
163    pthread_mutex_destroy(&jcr->mutex);
164
165    close_msg(jcr);                    /* close messages for this job */
166
167    /* do this after closing messages */
168    if (jcr->client_name) {
169       free_pool_memory(jcr->client_name);
170       jcr->client_name = NULL;
171    }
172
173    if (jcr->sd_auth_key) {
174       free(jcr->sd_auth_key);
175       jcr->sd_auth_key = NULL;
176    }
177    if (jcr->VolumeName) {
178       free_pool_memory(jcr->VolumeName);
179       jcr->VolumeName = NULL;
180    }
181
182    if (jcr->dir_bsock) {
183       bnet_close(jcr->dir_bsock);
184       jcr->dir_bsock = NULL;
185    }
186    if (jcr->errmsg) {
187       free_pool_memory(jcr->errmsg);
188       jcr->errmsg = NULL;
189    }
190    if (jcr->where) {
191       free(jcr->where);
192       jcr->where = NULL;
193    }
194    if (jcr->cached_path) {
195       free_pool_memory(jcr->cached_path);
196       jcr->cached_path = NULL;
197       jcr->cached_pnl = 0;
198    }
199    free_getuser_cache();
200    free_getgroup_cache();
201    free(jcr);
202 }
203
204 /* 
205  * Global routine to free a jcr
206  */
207 #ifdef DEBUG
208 void b_free_jcr(char *file, int line, JCR *jcr)
209 {
210    Dmsg3(200, "Enter free_jcr 0x%x from %s:%d\n", jcr, file, line);
211
212 #else
213
214 void free_jcr(JCR *jcr)
215 {
216
217    Dmsg1(200, "Enter free_jcr 0x%x\n", jcr);
218
219 #endif
220    struct s_last_job *je;
221
222    P(mutex);
223    jcr->use_count--;                  /* decrement use count */
224    Dmsg3(200, "Dec jcr 0x%x use_count=%d jobid=%d\n", jcr, jcr->use_count, jcr->JobId);
225    if (jcr->use_count > 0) {          /* if in use */
226       V(mutex);
227       Dmsg2(200, "jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
228       return;
229    }
230    remove_jcr(jcr);
231
232    Dmsg1(200, "End job=%d\n", jcr->JobId);
233    if (jcr->daemon_free_jcr) {
234       jcr->daemon_free_jcr(jcr);      /* call daemon free routine */
235    }
236
237    free_common_jcr(jcr);
238
239    /* Keep list of last jobs, but not Console where JobId==0 */
240    if (last_job.JobId > 0) {
241       je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
242       memcpy((char *)je, (char *)&last_job, sizeof(last_job));
243       last_jobs->append(je);
244       if (last_jobs->size() > MAX_LAST_JOBS) {
245          last_jobs->remove(last_jobs->first());
246       }
247       last_job.JobId = 0;             /* zap last job */
248    }
249    close_msg(NULL);                   /* flush any daemon messages */
250    V(mutex);
251    Dmsg0(200, "Exit free_jcr\n");
252 }
253
254
255 /* 
256  * Global routine to free a jcr
257  *  JCR chain is already locked
258  */
259 void free_locked_jcr(JCR *jcr)
260 {
261    jcr->use_count--;                  /* decrement use count */
262    Dmsg2(200, "Dec jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
263    if (jcr->use_count > 0) {          /* if in use */
264       return;
265    }
266    remove_jcr(jcr);
267    jcr->daemon_free_jcr(jcr);         /* call daemon free routine */
268    free_common_jcr(jcr);
269 }
270
271
272
273
274 /*
275  * Given a JobId, find the JCR      
276  *   Returns: jcr on success
277  *            NULL on failure
278  */
279 JCR *get_jcr_by_id(uint32_t JobId)
280 {
281    JCR *jcr;       
282
283    P(mutex);
284    for (jcr = jobs; jcr; jcr=jcr->next) {
285       if (jcr->JobId == JobId) {
286          jcr->use_count++;
287          Dmsg2(200, "Inc jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
288          break;
289       }
290    }
291    V(mutex);
292    return jcr; 
293 }
294
295 /*
296  * Given a SessionId and SessionTime, find the JCR      
297  *   Returns: jcr on success
298  *            NULL on failure
299  */
300 JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime)
301 {
302    JCR *jcr;       
303
304    P(mutex);
305    for (jcr = jobs; jcr; jcr=jcr->next) {
306       if (jcr->VolSessionId == SessionId && 
307           jcr->VolSessionTime == SessionTime) {
308          jcr->use_count++;
309          Dmsg2(200, "Inc jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
310          break;
311       }
312    }
313    V(mutex);
314    return jcr; 
315 }
316
317
318 /*
319  * Given a Job, find the JCR      
320  *  compares on the number of characters in Job
321  *  thus allowing partial matches.
322  *   Returns: jcr on success
323  *            NULL on failure
324  */
325 JCR *get_jcr_by_partial_name(char *Job)
326 {
327    JCR *jcr;       
328    int len;
329
330    if (!Job) {
331       return NULL;
332    }
333    P(mutex);
334    len = strlen(Job);
335    for (jcr = jobs; jcr; jcr=jcr->next) {
336       if (strncmp(Job, jcr->Job, len) == 0) {
337          jcr->use_count++;
338          Dmsg2(200, "Inc jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
339          break;
340       }
341    }
342    V(mutex);
343    return jcr; 
344 }
345
346
347 /*
348  * Given a Job, find the JCR      
349  *  requires an exact match of names.
350  *   Returns: jcr on success
351  *            NULL on failure
352  */
353 JCR *get_jcr_by_full_name(char *Job)
354 {
355    JCR *jcr;       
356
357    if (!Job) {
358       return NULL;
359    }
360    P(mutex);
361    for (jcr = jobs; jcr; jcr=jcr->next) {
362       if (strcmp(jcr->Job, Job) == 0) {
363          jcr->use_count++;
364          Dmsg2(200, "Inc jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
365          break;
366       }
367    }
368    V(mutex);
369    return jcr; 
370 }
371
372 void set_jcr_job_status(JCR *jcr, int JobStatus)
373 {
374    /*
375     * For a set of errors, ... keep the current status
376     *   so it isn't lost. For all others, set it.
377     */
378    switch (jcr->JobStatus) {
379    case JS_ErrorTerminated:
380    case JS_Error:
381    case JS_FatalError:
382    case JS_Differences:
383    case JS_Canceled:
384       break;
385    default:
386       jcr->JobStatus = JobStatus;
387    }
388 }
389
390 /* 
391  * Lock the chain
392  */
393 void lock_jcr_chain()
394 {
395    P(mutex);
396 }
397
398 /*
399  * Unlock the chain
400  */
401 void unlock_jcr_chain()
402 {
403    V(mutex);
404 }
405
406
407 JCR *get_next_jcr(JCR *jcr)
408 {
409    JCR *rjcr;
410
411    if (jcr == NULL) {
412       rjcr = jobs;
413    } else {
414       rjcr = jcr->next;
415    }
416    if (rjcr) {
417       rjcr->use_count++;
418       Dmsg1(200, "Inc jcr use_count=%d\n", rjcr->use_count);
419    }
420    return rjcr;
421 }