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