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