]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/expand.c
Fix bug #2343 where truncate of explicit Volume name truncates non-purged volumes
[bacula/bacula] / bacula / src / dird / expand.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Bacula Director -- expand.c -- does variable expansion
22  *    in particular for the LabelFormat specification.
23  *
24  *     Kern Sibbald, June MMIII
25  */
26
27 #include "bacula.h"
28 #include "dird.h"
29
30
31
32 static int date_item(JCR *jcr, int code,
33               const char **val_ptr, int *val_len, int *val_size)
34 {
35    struct tm tm;
36    time_t now = time(NULL);
37    (void)localtime_r(&now, &tm);
38    int val = 0;
39    char buf[10];
40
41    switch (code) {
42    case 1:                            /* year */
43       val = tm.tm_year + 1900;
44       break;
45    case 2:                            /* month */
46       val = tm.tm_mon + 1;
47       break;
48    case 3:                            /* day */
49       val = tm.tm_mday;
50       break;
51    case 4:                            /* hour */
52       val = tm.tm_hour;
53       break;
54    case 5:                            /* minute */
55       val = tm.tm_min;
56       break;
57    case 6:                            /* second */
58       val = tm.tm_sec;
59       break;
60    case 7:                            /* Week day */
61       val = tm.tm_wday;
62       break;
63    }
64    bsnprintf(buf, sizeof(buf), "%d", val);
65    *val_ptr = bstrdup(buf);
66    *val_len = strlen(buf);
67    *val_size = *val_len + 1;
68    return 1;
69 }
70
71 static int job_item(JCR *jcr, int code,
72               const char **val_ptr, int *val_len, int *val_size)
73 {
74    const char *str = " ";
75    char buf[20];
76
77    switch (code) {
78    case 1:                            /* Job */
79       str = jcr->job->name();
80       break;
81    case 2:                            /* Director's name */
82       str = my_name;
83       break;
84    case 3:                            /* level */
85       str = job_level_to_str(jcr->getJobLevel());
86       break;
87    case 4:                            /* type */
88       str = job_type_to_str(jcr->getJobType());
89       break;
90    case 5:                            /* JobId */
91       bsnprintf(buf, sizeof(buf), "%d", jcr->JobId);
92       str = buf;
93       break;
94    case 6:                            /* Client */
95       str = jcr->client->name();
96       if (!str) {
97          str = " ";
98       }
99       break;
100    case 7:                            /* NumVols */
101       bsnprintf(buf, sizeof(buf), "%d", jcr->NumVols);
102       str = buf;
103       break;
104    case 8:                            /* Pool */
105       str = jcr->pool->name();
106       break;
107    case 9:                            /* Storage */
108       if (jcr->wstore) {
109          str = jcr->wstore->name();
110       } else {
111          str = jcr->rstore->name();
112       }
113       break;
114    case 10:                           /* Catalog */
115       str = jcr->catalog->name();
116       break;
117    case 11:                           /* MediaType */
118       if (jcr->wstore) {
119          str = jcr->wstore->media_type;
120       } else {
121          str = jcr->rstore->media_type;
122       }
123       break;
124    case 12:                           /* JobName */
125       str = jcr->Job;
126       break;
127    }
128    *val_ptr = bstrdup(str);
129    *val_len = strlen(str);
130    *val_size = *val_len + 1;
131    return 1;
132 }
133
134 struct s_built_in_vars {const char *var_name; int code; int (*func)(JCR *jcr, int code,
135                          const char **val_ptr, int *val_len, int *val_size);};
136
137 /*
138  * Table of build in variables
139  */
140 static struct s_built_in_vars built_in_vars[] = {
141    { NT_("Year"),       1, date_item},
142    { NT_("Month"),      2, date_item},
143    { NT_("Day"),        3, date_item},
144    { NT_("Hour"),       4, date_item},
145    { NT_("Minute"),     5, date_item},
146    { NT_("Second"),     6, date_item},
147    { NT_("WeekDay"),    7, date_item},
148
149    { NT_("Job"),        1, job_item},
150    { NT_("Dir"),        2, job_item},
151    { NT_("Level"),      3, job_item},
152    { NT_("Type"),       4, job_item},
153    { NT_("JobId"),      5, job_item},
154    { NT_("Client"),     6, job_item},
155    { NT_("NumVols"),    7, job_item},
156    { NT_("Pool"),       8, job_item},
157    { NT_("Storage"),    9, job_item},
158    { NT_("Catalog"),   10, job_item},
159    { NT_("MediaType"), 11, job_item},
160    { NT_("JobName"),   12, job_item},
161
162    { NULL, 0, NULL}
163 };
164
165
166 /*
167  * Search the table of built-in variables, and if found,
168  *   call the appropriate subroutine to do the work.
169  */
170 static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx,
171           const char *var_ptr, int var_len, int var_index,
172           const char **val_ptr, int *val_len, int *val_size)
173 {
174    JCR *jcr = (JCR *)my_ctx;
175    int stat;
176
177    for (int i=0; _(built_in_vars[i].var_name); i++) {
178       if (strncmp(_(built_in_vars[i].var_name), var_ptr, var_len) == 0) {
179          stat = (*built_in_vars[i].func)(jcr, built_in_vars[i].code,
180             val_ptr, val_len, val_size);
181          if (stat) {
182             return VAR_OK;
183          }
184          break;
185       }
186    }
187    return VAR_ERR_UNDEFINED_VARIABLE;
188 }
189
190
191 /*
192  * Search counter variables
193  */
194 static var_rc_t lookup_counter_var(var_t *ctx, void *my_ctx,
195           const char *var_ptr, int var_len, int var_inc, int var_index,
196           const char **val_ptr, int *val_len, int *val_size)
197 {
198    char buf[MAXSTRING];
199    var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE;
200
201    if (var_len > (int)sizeof(buf) - 1) {
202        return VAR_ERR_OUT_OF_MEMORY;
203    }
204    memcpy(buf, var_ptr, var_len);
205    buf[var_len] = 0;
206    LockRes();
207    for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
208       if (strcmp(counter->name(), buf) == 0) {
209          Dmsg2(100, "Counter=%s val=%d\n", buf, counter->CurrentValue);
210          /* -1 => return size of array */
211         if (var_index == -1) {
212             bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
213             *val_len = bsnprintf(buf, sizeof(buf), "%d", strlen(buf));
214             *val_ptr = buf;
215             *val_size = 0;                  /* don't try to free val_ptr */
216             return VAR_OK;
217          } else {
218             bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
219             *val_ptr = bstrdup(buf);
220             *val_len = strlen(buf);
221             *val_size = *val_len + 1;
222          }
223          if (var_inc) {               /* increment the variable? */
224             if (counter->CurrentValue == counter->MaxValue) {
225                counter->CurrentValue = counter->MinValue;
226             } else {
227                counter->CurrentValue++;
228             }
229             if (counter->Catalog) {   /* update catalog if need be */
230                COUNTER_DBR cr;
231                JCR *jcr = (JCR *)my_ctx;
232                memset(&cr, 0, sizeof(cr));
233                bstrncpy(cr.Counter, counter->name(), sizeof(cr.Counter));
234                cr.MinValue = counter->MinValue;
235                cr.MaxValue = counter->MaxValue;
236                cr.CurrentValue = counter->CurrentValue;
237                Dmsg1(100, "New value=%d\n", cr.CurrentValue);
238                if (counter->WrapCounter) {
239                   bstrncpy(cr.WrapCounter, counter->WrapCounter->name(), sizeof(cr.WrapCounter));
240                } else {
241                   cr.WrapCounter[0] = 0;
242                }
243                if (!db_update_counter_record(jcr, jcr->db, &cr)) {
244                   Jmsg(jcr, M_ERROR, 0, _("Count not update counter %s: ERR=%s\n"),
245                      counter->name(), db_strerror(jcr->db));
246                }
247             }
248          }
249          stat = VAR_OK;
250          break;
251       }
252    }
253    UnlockRes();
254    return stat;
255 }
256
257
258 /*
259  * Called here from "core" expand code to look up a variable
260  */
261 static var_rc_t lookup_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], *val, *p, *v;
266    var_rc_t stat;
267    int count;
268
269    /* Note, if val_size > 0 and val_ptr!=NULL, the core code will free() it */
270    if ((stat = lookup_built_in_var(ctx, my_ctx, var_ptr, var_len, var_index,
271         val_ptr, val_len, val_size)) == VAR_OK) {
272       return VAR_OK;
273    }
274
275    if ((stat = lookup_counter_var(ctx, my_ctx, var_ptr, var_len, var_inc, var_index,
276         val_ptr, val_len, val_size)) == VAR_OK) {
277       return VAR_OK;
278    }
279
280    /* Look in environment */
281    if (var_len > (int)sizeof(buf) - 1) {
282        return VAR_ERR_OUT_OF_MEMORY;
283    }
284    memcpy(buf, var_ptr, var_len + 1);
285    buf[var_len] = 0;
286    Dmsg1(100, "Var=%s\n", buf);
287
288    if ((val = getenv(buf)) == NULL) {
289        return VAR_ERR_UNDEFINED_VARIABLE;
290    }
291    /* He wants to index the "array" */
292    count = 1;
293    /* Find the size of the "array"
294     *   each element is separated by a |
295     */
296    for (p = val; *p; p++) {
297       if (*p == '|') {
298          count++;
299       }
300    }
301    Dmsg3(100, "For %s, reqest index=%d have=%d\n",
302       buf, var_index, count);
303
304    /* -1 => return size of array */
305    if (var_index == -1) {
306       int len;
307       if (count == 1) {               /* if not array */
308          len = strlen(val);           /* return length of string */
309       } else {
310          len = count;                 /* else return # array items */
311       }
312       *val_len = bsnprintf(buf, sizeof(buf), "%d", len);
313       *val_ptr = buf;
314       *val_size = 0;                  /* don't try to free val_ptr */
315       return VAR_OK;
316    }
317
318
319    if (var_index < -1 || var_index > --count) {
320 //    return VAR_ERR_SUBMATCH_OUT_OF_RANGE;
321       return VAR_ERR_UNDEFINED_VARIABLE;
322    }
323    /* Now find the particular item (var_index) he wants */
324    count = 0;
325    for (p=val; *p; ) {
326       if (*p == '|') {
327          if (count < var_index) {
328             val = ++p;
329             count++;
330             continue;
331          }
332          break;
333       }
334       p++;
335    }
336    if (p-val > (int)sizeof(buf) - 1) {
337        return VAR_ERR_OUT_OF_MEMORY;
338    }
339    Dmsg2(100, "val=%s len=%d\n", val, p-val);
340    /* Make a copy of item, and pass it back */
341    v = (char *)malloc(p-val+1);
342    memcpy(v, val, p-val);
343    v[p-val] = 0;
344    *val_ptr = v;
345    *val_len = p-val;
346    *val_size = p-val+1;
347    Dmsg1(100, "v=%s\n", v);
348    return VAR_OK;
349 }
350
351 /*
352  * Called here to do a special operation on a variable
353  *   op_ptr  points to the special operation code (not EOS terminated)
354  *   arg_ptr points to argument to special op code
355  *   val_ptr points to the value string
356  *   out_ptr points to string to be returned
357  */
358 static var_rc_t operate_var(var_t *var, void *my_ctx,
359           const char *op_ptr, int op_len,
360           const char *arg_ptr, int arg_len,
361           const char *val_ptr, int val_len,
362           char **out_ptr, int *out_len, int *out_size)
363 {
364    var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION;
365    Dmsg0(100, "Enter operate_var\n");
366    if (!val_ptr) {
367       *out_size = 0;
368       return stat;
369    }
370    if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) {
371       char buf[MAXSTRING];
372       if (val_len > (int)sizeof(buf) - 1) {
373           return VAR_ERR_OUT_OF_MEMORY;
374       }
375       memcpy(buf, arg_ptr, arg_len);
376       buf[arg_len] = 0;
377       Dmsg1(100, "Arg=%s\n", buf);
378       memcpy(buf, val_ptr, val_len);
379       buf[val_len] = 0;
380       Dmsg1(100, "Val=%s\n", buf);
381       LockRes();
382       for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
383          if (strcmp(counter->name(), buf) == 0) {
384             Dmsg2(100, "counter=%s val=%s\n", counter->name(), buf);
385             break;
386          }
387       }
388       UnlockRes();
389       return stat;
390    }
391    *out_size = 0;
392    return stat;
393 }
394
395
396 /*
397  * Expand an input line and return it.
398  *
399  *  Returns: 0 on failure
400  *           1 on success and exp has expanded input
401  */
402 int variable_expansion(JCR *jcr, char *inp, POOLMEM **exp)
403 {
404    var_t *var_ctx;
405    var_rc_t stat;
406    char *outp;
407    int in_len, out_len;
408    int rtn_stat = 0;
409
410    in_len = strlen(inp);
411    outp = NULL;
412    out_len = 0;
413
414    /* create context */
415    if ((stat = var_create(&var_ctx)) != VAR_OK) {
416        Jmsg(jcr, M_ERROR, 0, _("Cannot create var context: ERR=%s\n"), var_strerror(var_ctx, stat));
417        goto bail_out;
418    }
419    /* define callback */
420    if ((stat = var_config(var_ctx, VAR_CONFIG_CB_VALUE, lookup_var, (void *)jcr)) != VAR_OK) {
421        Jmsg(jcr, M_ERROR, 0, _("Cannot set var callback: ERR=%s\n"), var_strerror(var_ctx, stat));
422        goto bail_out;
423    }
424
425    /* define special operations */
426    if ((stat = var_config(var_ctx, VAR_CONFIG_CB_OPERATION, operate_var, (void *)jcr)) != VAR_OK) {
427        Jmsg(jcr, M_ERROR, 0, _("Cannot set var operate: ERR=%s\n"), var_strerror(var_ctx, stat));
428        goto bail_out;
429    }
430
431    /* unescape in place */
432    if ((stat = var_unescape(var_ctx, inp, in_len, inp, in_len+1, 0)) != VAR_OK) {
433        Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
434        goto bail_out;
435    }
436
437    in_len = strlen(inp);
438
439    /* expand variables */
440    if ((stat = var_expand(var_ctx, inp, in_len, &outp, &out_len, 0)) != VAR_OK) {
441        Jmsg(jcr, M_ERROR, 0, _("Cannot expand expression \"%s\": ERR=%s\n"),
442           inp, var_strerror(var_ctx, stat));
443        goto bail_out;
444    }
445
446    /* unescape once more in place */
447    if ((stat = var_unescape(var_ctx, outp, out_len, outp, out_len+1, 1)) != VAR_OK) {
448        Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
449        goto bail_out;
450    }
451
452    pm_strcpy(exp, outp);
453
454    rtn_stat = 1;
455
456 bail_out:
457    /* destroy expansion context */
458    if ((stat = var_destroy(var_ctx)) != VAR_OK) {
459        Jmsg(jcr, M_ERROR, 0, _("Cannot destroy var context: ERR=%s\n"), var_strerror(var_ctx, stat));
460    }
461    if (outp) {
462       free(outp);
463    }
464    return rtn_stat;
465 }