]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/newvol.c
New var.c file + implement multiple simultaneous jobs
[bacula/bacula] / bacula / src / dird / newvol.c
1 /*
2  *
3  *   Bacula Director -- newvol.c -- creates new Volumes in
4  *    catalog Media table from the LabelFormat specification.
5  *
6  *     Kern Sibbald, May MMI
7  *
8  *    This routine runs as a thread and must be thread reentrant.
9  *
10  *  Basic tasks done here:
11  *      If possible create a new Media entry
12  *
13  *   Version $Id$
14  */
15 /*
16    Copyright (C) 2000-2003 Kern Sibbald and John Walker
17
18    This program is free software; you can redistribute it and/or
19    modify it under the terms of the GNU General Public License as
20    published by the Free Software Foundation; either version 2 of
21    the License, or (at your option) any later version.
22
23    This program is distributed in the hope that it will be useful,
24    but WITHOUT ANY WARRANTY; without even the implied warranty of
25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26    General Public License for more details.
27
28    You should have received a copy of the GNU General Public
29    License along with this program; if not, write to the Free
30    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
31    MA 02111-1307, USA.
32
33  */
34
35 #include "bacula.h"
36 #include "dird.h"
37
38 /* Forward referenced functions */
39 static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr);
40 static int perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr);
41
42
43 /*
44  * Really crude automatic Volume name creation using
45  *  LabelFormat. We assume that if this routine is being
46  *  called the Volume will be labeled, so we set the LabelDate.
47  */
48 int newVolume(JCR *jcr, MEDIA_DBR *mr)
49 {
50    POOL_DBR pr;
51
52    memset(&pr, 0, sizeof(pr));
53
54    /* See if we can create a new Volume */
55    db_lock(jcr->db);
56    pr.PoolId = jcr->PoolId;
57    if (db_get_pool_record(jcr, jcr->db, &pr) && pr.LabelFormat[0] &&
58        pr.LabelFormat[0] != '*') {
59       if (pr.MaxVols == 0 || pr.NumVols < pr.MaxVols) {
60          memset(mr, 0, sizeof(MEDIA_DBR));
61          set_pool_dbr_defaults_in_media_dbr(mr, &pr);
62          mr->LabelDate = time(NULL);
63          bstrncpy(mr->MediaType, jcr->store->media_type, sizeof(mr->MediaType));
64          /* Check for special characters */
65          if (is_volume_name_legal(NULL, pr.LabelFormat)) {
66             /* No special characters, so apply simple algorithm */
67             if (!create_simple_name(jcr, mr, &pr)) {
68                goto bail_out;
69             }
70          } else {  /* try full substitution */
71             /* Found special characters, so try substitution */
72             if (!perform_full_name_substitution(jcr, mr, &pr)) { 
73                goto bail_out;
74             }
75             if (!is_volume_name_legal(NULL, mr->VolumeName)) {
76                Jmsg(jcr, M_ERROR, 0, _("Illegal character in Volume name \"%s\"\n"),
77                   mr->VolumeName);
78                goto bail_out;
79             }
80          }
81          pr.NumVols++;
82          if (db_create_media_record(jcr, jcr->db, mr) &&
83             db_update_pool_record(jcr, jcr->db, &pr)) {
84             db_unlock(jcr->db);
85             Jmsg(jcr, M_INFO, 0, _("Created new Volume \"%s\" in catalog.\n"), mr->VolumeName);
86             Dmsg1(90, "Created new Volume=%s\n", mr->VolumeName);
87             return 1;
88          } else {
89             Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
90          }
91       }
92    }
93 bail_out:
94    db_unlock(jcr->db);
95    return 0;   
96 }
97
98 static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr)
99 {
100    char name[MAXSTRING];
101    char num[20];
102
103    /* See if volume already exists */
104    mr->VolumeName[0] = 0;
105    bstrncpy(name, pr->LabelFormat, sizeof(name));
106    for (int i=pr->NumVols+1; i<(int)pr->NumVols+11; i++) {
107       MEDIA_DBR tmr;
108       memset(&tmr, 0, sizeof(tmr));
109       sprintf(num, "%04d", i);
110       bstrncpy(tmr.VolumeName, name, sizeof(tmr.VolumeName));
111       bstrncat(tmr.VolumeName, num, sizeof(tmr.VolumeName));
112       if (db_get_media_record(jcr, jcr->db, &tmr)) {
113          Jmsg(jcr, M_WARNING, 0, 
114              _("Wanted to create Volume \"%s\", but it already exists. Trying again.\n"), 
115              tmr.VolumeName);
116          continue;
117       }
118       bstrncpy(mr->VolumeName, name, sizeof(mr->VolumeName));
119       bstrncat(mr->VolumeName, num, sizeof(mr->VolumeName));
120       break;                    /* Got good name */
121    }
122    if (mr->VolumeName[0] == 0) {
123       Jmsg(jcr, M_ERROR, 0, _("Too many failures. Giving up creating Volume name.\n"));
124       return 0;
125    }
126    return 1;
127 }
128
129 static int date_item(JCR *jcr, int code, 
130               const char **val_ptr, int *val_len, int *val_size)
131 {
132    struct tm tm;
133    time_t now = time(NULL);
134    localtime_r(&now, &tm);
135    int val = 0;
136    char buf[10];
137
138    switch (code) {
139    case 1:                            /* year */
140       val = tm.tm_year + 1900;
141       break;
142    case 2:                            /* month */
143       val = tm.tm_mon + 1;
144       break;
145    case 3:                            /* day */
146       val = tm.tm_mday;
147       break;
148    case 4:                            /* hour */
149       val = tm.tm_hour;
150       break;
151    case 5:                            /* minute */
152       val = tm.tm_min;
153       break;
154    case 6:                            /* second */
155       val = tm.tm_sec;
156       break;
157    case 7:                            /* Week day */
158       val = tm.tm_wday;
159       break;
160    }
161    bsnprintf(buf, sizeof(buf), "%d", val);
162    *val_ptr = bstrdup(buf);
163    *val_len = strlen(buf);
164    *val_size = *val_len;
165    return 1;
166 }
167
168 static int job_item(JCR *jcr, int code, 
169               const char **val_ptr, int *val_len, int *val_size)
170 {
171    char *str = " ";
172    char buf[20];
173
174    switch (code) {
175    case 1:                            /* Job */
176       str = jcr->Job;
177       break;
178    case 2:                            /* Director's name */
179       str = my_name;
180       break;
181    case 3:                            /* level */
182       str = job_level_to_str(jcr->JobLevel);
183       break;
184    case 4:                            /* type */
185       str = job_type_to_str(jcr->JobType);
186       break;
187    case 5:                            /* JobId */
188       bsnprintf(buf, sizeof(buf), "%d", jcr->JobId);
189       str = buf;
190       break;
191    case 6:                            /* Client */
192       str = jcr->client_name;
193       if (!str) {
194          str = " ";
195       }
196       break;
197    case 7:                            /* NumVols */
198       bsnprintf(buf, sizeof(buf), "%d", jcr->NumVols);
199       str = buf;
200       break;
201    case 8:                            /* Pool */
202       str = jcr->client->hdr.name;   
203       break;
204    }
205    *val_ptr = bstrdup(str);
206    *val_len = strlen(str);
207    *val_size = *val_len;
208    return 1;
209 }
210
211
212 struct s_built_in_vars {char *var_name; int code; int (*func)(JCR *jcr, int code,
213                          const char **val_ptr, int *val_len, int *val_size);};
214
215 static struct s_built_in_vars built_in_vars[] = {
216    { N_("Year"),    1, date_item},
217    { N_("Month"),   2, date_item},
218    { N_("Day"),     3, date_item},
219    { N_("Hour"),    4, date_item},
220    { N_("Minute"),  5, date_item},
221    { N_("Second"),  6, date_item},
222    { N_("WeekDay"), 7, date_item},
223
224    { N_("Job"),     1, job_item},
225    { N_("Dir"),     2, job_item},
226    { N_("Level"),   3, job_item},
227    { N_("Type"),    4, job_item},
228    { N_("JobId"),   5, job_item},
229    { N_("Client"),  6, job_item},
230    { N_("NumVols"), 7, job_item},
231    { N_("Pool"),    8, job_item},
232
233    { NULL, 0, NULL}
234 };
235
236
237 static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx, 
238           const char *var_ptr, int var_len, int var_index, 
239           const char **val_ptr, int *val_len, int *val_size)
240 {
241    JCR *jcr = (JCR *)my_ctx;
242    int stat;
243
244    for (int i=0; _(built_in_vars[i].var_name); i++) {
245       if (strncmp(_(built_in_vars[i].var_name), var_ptr, var_len) == 0) {
246          stat = (*built_in_vars[i].func)(jcr, built_in_vars[i].code,
247             val_ptr, val_len, val_size);
248          if (stat) {
249             return VAR_OK;
250          }
251          break;
252       }
253    }
254    return VAR_ERR_UNDEFINED_VARIABLE;
255 }
256
257
258 /*
259  * Search counter variables 
260  */
261 static var_rc_t lookup_counter_var(var_t *ctx, void *my_ctx, 
262           const char *var_ptr, int var_len, int var_inc, int var_index, 
263           const char **val_ptr, int *val_len, int *val_size)
264 {
265    char buf[MAXSTRING];
266    var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE;
267
268    if (var_len > (int)sizeof(buf) - 1) {
269        return VAR_ERR_OUT_OF_MEMORY;
270    }
271    memcpy(buf, var_ptr, var_len);
272    buf[var_len] = 0;
273    LockRes();
274    for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
275       if (strcmp(counter->hdr.name, buf) == 0) {
276          bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
277          *val_ptr = bstrdup(buf);
278          *val_len = strlen(buf);
279          *val_size = *val_len;
280          if (var_inc) {
281             COUNTER_DBR cr;
282             JCR *jcr = (JCR *)my_ctx;
283             memset(&cr, 0, sizeof(cr));
284             bstrncpy(cr.Counter, counter->hdr.name, sizeof(cr.Counter));
285             cr.MinValue = counter->MinValue;
286             cr.MaxValue = counter->MaxValue;
287             cr.CurrentValue = ++counter->CurrentValue;
288             bstrncpy(cr.WrapCounter, counter->WrapCounter->hdr.name, sizeof(cr.WrapCounter));
289             if (!db_update_counter_record(jcr, jcr->db, &cr)) {
290                Jmsg(jcr, M_ERROR, 0, _("Count not update counter %s: ERR=%s\n"),
291                   counter->hdr.name, db_strerror(jcr->db));
292             }
293          }  
294          stat = VAR_OK;
295          break;
296       }
297    }
298    UnlockRes();
299    return stat;
300 }
301
302
303 /*
304  * Called here to look up a variable   
305  */
306 static var_rc_t lookup_var(var_t *ctx, void *my_ctx, 
307           const char *var_ptr, int var_len, int var_inc, int var_index, 
308           const char **val_ptr, int *val_len, int *val_size)
309 {
310    char buf[MAXSTRING], *val, *p, *v;
311    var_rc_t stat;
312    int count;
313
314    if ((stat = lookup_built_in_var(ctx, my_ctx, var_ptr, var_len, var_index,
315         val_ptr, val_len, val_size)) == VAR_OK) {
316       return VAR_OK;
317    }
318
319    if ((stat = lookup_counter_var(ctx, my_ctx, var_ptr, var_len, var_inc, var_index,
320         val_ptr, val_len, val_size)) == VAR_OK) {
321       return VAR_OK;
322    }
323
324    /* Look in environment */
325    if (var_len > (int)sizeof(buf) - 1) {
326        return VAR_ERR_OUT_OF_MEMORY;
327    }
328    memcpy(buf, var_ptr, var_len + 1);
329    buf[var_len] = 0;
330 // Dmsg1(000, "Var=%s\n", buf);
331
332    if ((val = getenv(buf)) == NULL) {
333        return VAR_ERR_UNDEFINED_VARIABLE;
334    }
335    if (var_index == 0) {
336       *val_ptr = val;
337       *val_len = strlen(val);
338       *val_size = 0;
339       return VAR_OK;
340    }
341    /* He wants to index the "array" */
342    count = 0;
343    /* Find the size of the "array"                           
344     *   each element is separated by a |  
345     */
346    for (p = val; *p; p++) {
347       if (*p == '|') {
348          count++;
349       }
350    }
351    count++;
352 // Dmsg3(000, "For %s, reqest index=%d have=%d\n",
353 //    buf, var_index, count);
354    if (var_index < 0 || var_index > count) {
355       return VAR_ERR_SUBMATCH_OUT_OF_RANGE;
356    }
357    /* Now find the particular item (var_index) he wants */
358    count = 1;
359    for (p=val; *p; ) {
360       if (*p == '|') {
361          if (count < var_index) {
362             val = ++p;
363             count++;
364             continue;
365          }
366          break;
367       }
368       p++;
369    }
370    if (p-val > (int)sizeof(buf) - 1) {
371        return VAR_ERR_OUT_OF_MEMORY;
372    }
373 // Dmsg2(000, "val=%s len=%d\n", val, p-val);
374    /* Make a copy of item, and pass it back */
375    v = (char *)malloc(p-val+1);
376    memcpy(v, val, p-val);
377    v[p-val] = 0;
378    *val_ptr = v;
379    *val_len = p-val;
380    *val_size = p-val;
381 // Dmsg1(000, "v=%s\n", v);
382    return VAR_OK;
383 }
384
385 /*
386  * Called here to do a special operation on a variable
387  *   op_ptr  points to the special operation code (not EOS terminated)
388  *   arg_ptr points to argument to special op code
389  *   val_ptr points to the value string
390  *   out_ptr points to string to be returned
391  */
392 static var_rc_t operate_var(var_t *var, void *my_ctx, 
393           const char *op_ptr, int op_len, 
394           const char *arg_ptr, int arg_len,
395           const char *val_ptr, int val_len, 
396           char **out_ptr, int *out_len, int *out_size)
397 {
398    var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION;
399    Dmsg0(000, "Enter operate_var\n");
400    if (!val_ptr) {
401       *out_size = 0;
402       return stat;
403    }
404    if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) {
405       char buf[MAXSTRING];
406       if (val_len > (int)sizeof(buf) - 1) {
407           return VAR_ERR_OUT_OF_MEMORY;
408       }
409       memcpy(buf, arg_ptr, arg_len);
410       buf[arg_len] = 0;
411       Dmsg1(000, "Arg=%s\n", buf);
412       memcpy(buf, val_ptr, val_len);
413       buf[val_len] = 0;   
414       Dmsg1(000, "Val=%s\n", buf);
415       LockRes();
416       for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
417          if (strcmp(counter->hdr.name, buf) == 0) {
418             Dmsg2(000, "counter=%s val=%s\n", counter->hdr.name, buf);
419             break;
420          }
421       }
422       UnlockRes();
423       return stat;
424    }
425    *out_size = 0;
426    return stat;
427 }
428
429 /*
430  * Perform full substitution on Label
431  */
432 static int perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr)
433 {
434    var_t *var_ctx;
435    var_rc_t stat;
436    char *inp, *outp;
437    int in_len, out_len;
438    int rtn_stat = 0;
439
440    inp = pr->LabelFormat;
441    in_len = strlen(inp);
442
443    outp = NULL;
444    out_len = 0;
445
446    jcr->NumVols = pr->NumVols;
447    /* create context */
448    if ((stat = var_create(&var_ctx)) != VAR_OK) {
449        Jmsg(jcr, M_ERROR, 0, _("Cannot create var context: ERR=%s\n"), var_strerror(var_ctx, stat));
450        goto bail_out;
451    }
452    /* define callback */
453    if ((stat = var_config(var_ctx, VAR_CONFIG_CB_VALUE, lookup_var, (void *)jcr)) != VAR_OK) {
454        Jmsg(jcr, M_ERROR, 0, _("Cannot set var callback: ERR=%s\n"), var_strerror(var_ctx, stat));
455        goto bail_out;
456    }
457
458
459    /* define special operations */
460    if ((stat = var_config(var_ctx, VAR_CONFIG_CB_OPERATION, operate_var, (void *)jcr)) != VAR_OK) {
461        Jmsg(jcr, M_ERROR, 0, _("Cannot set var operate: ERR=%s\n"), var_strerror(var_ctx, stat));
462        goto bail_out;
463    }
464
465    /* unescape in place */
466    if ((stat = var_unescape(var_ctx, inp, in_len, inp, in_len+1, 0)) != VAR_OK) {
467        Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
468        goto bail_out;
469    }
470
471    in_len = strlen(inp);
472
473    /* expand variables */
474    if ((stat = var_expand(var_ctx, inp, in_len, &outp, &out_len, 1)) != VAR_OK) {
475        Jmsg(jcr, M_ERROR, 0, _("Cannot expand LabelFormat \"%s\": ERR=%s\n"), 
476           inp, var_strerror(var_ctx, stat));
477        goto bail_out;
478    }
479
480    /* unescape once more in place */
481    if ((stat = var_unescape(var_ctx, outp, out_len, outp, out_len+1, 1)) != VAR_OK) {
482        Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
483        goto bail_out;
484    }
485
486    bstrncpy(mr->VolumeName, outp, sizeof(mr->VolumeName));
487
488    rtn_stat = 1;  
489
490 bail_out:
491    /* destroy expansion context */
492    if ((stat = var_destroy(var_ctx)) != VAR_OK) {
493        Jmsg(jcr, M_ERROR, 0, _("Cannot destroy var context: ERR=%s\n"), var_strerror(var_ctx, stat));
494    }
495    if (outp) {
496       free(outp);
497    }
498    return rtn_stat;
499 }