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