]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/jcr.c
Add this for symmetry
[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 static int num_last_jobs = 0;
39 #define MAX_LAST_JOBS 10
40
41 static JCR *jobs = NULL;              /* pointer to JCR chain */
42 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
43
44 void init_last_jobs_list()
45 {
46    struct s_last_job *job_entry;
47    last_jobs = new dlist(job_entry,  &job_entry->link);
48    memset(&last_job, 0, sizeof(last_job));
49 }
50
51 void term_last_jobs_list()
52 {
53    for (void *je=NULL; (je=last_jobs->next(je)); ) {
54       free(je);                     
55    }
56    delete last_jobs;
57 }
58
59 void lock_last_jobs_list() 
60 {
61    P(mutex);
62 }
63
64 void unlock_last_jobs_list() 
65 {
66    V(mutex);
67 }
68
69 /*
70  * Create a Job Control Record and link it into JCR chain
71  * Returns newly allocated JCR
72  * Note, since each daemon has a different JCR, he passes
73  *  us the size.
74  */
75 JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr)
76 {
77    JCR *jcr;
78    struct sigaction sigtimer;
79
80    Dmsg0(200, "Enter new_jcr\n");
81    jcr = (JCR *)malloc(size);
82    memset(jcr, 0, size);
83    jcr->my_thread_id = pthread_self();
84    jcr->sched_time = time(NULL);
85    jcr->daemon_free_jcr = daemon_free_jcr;    /* plug daemon free routine */
86    jcr->use_count = 1;
87    pthread_mutex_init(&(jcr->mutex), NULL);
88    jcr->JobStatus = JS_Created;       /* ready to run */
89    jcr->VolumeName = get_pool_memory(PM_FNAME);
90    jcr->VolumeName[0] = 0;
91    jcr->errmsg = get_pool_memory(PM_MESSAGE);
92    jcr->errmsg[0] = 0;
93    strcpy(jcr->Job, "*Console*");     /* default */
94
95    sigtimer.sa_flags = 0;
96    sigtimer.sa_handler = timeout_handler;
97    sigfillset(&sigtimer.sa_mask);
98    sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL);
99
100    P(mutex);
101    jcr->prev = NULL;
102    jcr->next = jobs;
103    if (jobs) {
104       jobs->prev = jcr;
105    }
106    jobs = jcr;
107    V(mutex);
108    return jcr;
109 }
110
111
112 /*
113  * Remove a JCR from the chain
114  * NOTE! The chain must be locked prior to calling
115  *       this routine.
116  */
117 static void remove_jcr(JCR *jcr)
118 {
119    Dmsg0(150, "Enter remove_jcr\n");
120    if (!jcr) {
121       Emsg0(M_ABORT, 0, "NULL jcr.\n");
122    }
123    if (!jcr->prev) {                  /* if no prev */
124       jobs = jcr->next;               /* set new head */
125    } else {
126       jcr->prev->next = jcr->next;    /* update prev */
127    }
128    if (jcr->next) {
129       jcr->next->prev = jcr->prev;
130    }
131    Dmsg0(150, "Leave remove_jcr\n");
132 }
133
134 /*
135  * Free stuff common to all JCRs.  N.B. Be careful to include only
136  *  generic stuff in the common part of the jcr. 
137  */
138 static void free_common_jcr(JCR *jcr)
139 {
140    /* Keep some statistics */
141    switch (jcr->JobType) {
142    case JT_BACKUP:
143    case JT_VERIFY:
144    case JT_RESTORE:
145    case JT_ADMIN:
146       last_job.NumJobs++;
147       last_job.JobType = jcr->JobType;
148       last_job.JobId = jcr->JobId;
149       last_job.VolSessionId = jcr->VolSessionId;
150       last_job.VolSessionTime = jcr->VolSessionTime;
151       bstrncpy(last_job.Job, jcr->Job, sizeof(last_job.Job));
152       last_job.JobFiles = jcr->JobFiles;
153       last_job.JobBytes = jcr->JobBytes;
154       last_job.JobStatus = jcr->JobStatus;
155       last_job.JobLevel = jcr->JobLevel;
156       last_job.start_time = jcr->start_time;
157       last_job.end_time = time(NULL);
158       break;
159    default:
160       break;
161    }
162    pthread_mutex_destroy(&jcr->mutex);
163
164    close_msg(jcr);                    /* close messages for this job */
165
166    /* do this after closing messages */
167    if (jcr->client_name) {
168       free_pool_memory(jcr->client_name);
169       jcr->client_name = NULL;
170    }
171
172    if (jcr->sd_auth_key) {
173       free(jcr->sd_auth_key);
174       jcr->sd_auth_key = NULL;
175    }
176    if (jcr->VolumeName) {
177       free_pool_memory(jcr->VolumeName);
178       jcr->VolumeName = NULL;
179    }
180
181    if (jcr->dir_bsock) {
182       bnet_close(jcr->dir_bsock);
183       jcr->dir_bsock = NULL;
184    }
185    if (jcr->errmsg) {
186       free_pool_memory(jcr->errmsg);
187       jcr->errmsg = NULL;
188    }
189    if (jcr->where) {
190       free(jcr->where);
191       jcr->where = NULL;
192    }
193    if (jcr->cached_path) {
194       free_pool_memory(jcr->cached_path);
195       jcr->cached_path = NULL;
196       jcr->cached_pnl = 0;
197    }
198    free_getuser_cache();
199    free_getgroup_cache();
200    free(jcr);
201 }
202
203 /* 
204  * Global routine to free a jcr
205  */
206 #ifdef DEBUG
207 void b_free_jcr(char *file, int line, JCR *jcr)
208 {
209    Dmsg3(200, "Enter free_jcr 0x%x from %s:%d\n", jcr, file, line);
210
211 #else
212
213 void free_jcr(JCR *jcr)
214 {
215
216    Dmsg1(200, "Enter free_jcr 0x%x\n", jcr);
217
218 #endif
219    struct s_last_job *je;
220
221    P(mutex);
222    jcr->use_count--;                  /* decrement use count */
223    Dmsg3(200, "Dec jcr 0x%x use_count=%d jobid=%d\n", jcr, jcr->use_count, jcr->JobId);
224    if (jcr->use_count > 0) {          /* if in use */
225       V(mutex);
226       Dmsg2(200, "jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
227       return;
228    }
229    remove_jcr(jcr);
230    V(mutex);
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    free_common_jcr(jcr);
237
238    P(mutex);
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 (++num_last_jobs > MAX_LAST_JOBS) {
245          last_jobs->remove(last_jobs->first());
246          num_last_jobs--;
247       }
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 }