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