]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/expand.c
Fix additional counter problem + fix pathconf() error bug
[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) 2000-2003 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    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;
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    char *str = " ";
78    char buf[20];
79
80    switch (code) {
81    case 1:                            /* Job */
82       str = jcr->job->hdr.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->hdr.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->hdr.name;   
109       break;
110    case 9:                            /* Storage */
111       str = jcr->store->hdr.name;
112       break;
113    case 10:                           /* Catalog */
114       str = jcr->catalog->hdr.name;
115       break;
116    case 11:                           /* MediaType */
117       str = jcr->store->media_type;
118       break;
119    case 12:                           /* JobName */
120       str = jcr->Job;
121       break;
122    }
123    *val_ptr = bstrdup(str);
124    *val_len = strlen(str);
125    *val_size = *val_len;
126    return 1;
127 }
128
129
130 struct s_built_in_vars {char *var_name; int code; int (*func)(JCR *jcr, int code,
131                          const char **val_ptr, int *val_len, int *val_size);};
132
133 static struct s_built_in_vars built_in_vars[] = {
134    { N_("Year"),       1, date_item},
135    { N_("Month"),      2, date_item},
136    { N_("Day"),        3, date_item},
137    { N_("Hour"),       4, date_item},
138    { N_("Minute"),     5, date_item},
139    { N_("Second"),     6, date_item},
140    { N_("WeekDay"),    7, date_item},
141
142    { N_("Job"),        1, job_item},
143    { N_("Dir"),        2, job_item},
144    { N_("Level"),      3, job_item},
145    { N_("Type"),       4, job_item},
146    { N_("JobId"),      5, job_item},
147    { N_("Client"),     6, job_item},
148    { N_("NumVols"),    7, job_item},
149    { N_("Pool"),       8, job_item},
150    { N_("Storage"),    9, job_item},
151    { N_("Catalog"),   10, job_item},
152    { N_("MediaType"), 11, job_item},
153    { N_("JobName"),   12, job_item},
154
155    { NULL, 0, NULL}
156 };
157
158
159 static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx, 
160           const char *var_ptr, int var_len, int var_index, 
161           const char **val_ptr, int *val_len, int *val_size)
162 {
163    JCR *jcr = (JCR *)my_ctx;
164    int stat;
165
166    for (int i=0; _(built_in_vars[i].var_name); i++) {
167       if (strncmp(_(built_in_vars[i].var_name), var_ptr, var_len) == 0) {
168          stat = (*built_in_vars[i].func)(jcr, built_in_vars[i].code,
169             val_ptr, val_len, val_size);
170          if (stat) {
171             return VAR_OK;
172          }
173          break;
174       }
175    }
176    return VAR_ERR_UNDEFINED_VARIABLE;
177 }
178
179
180 /*
181  * Search counter variables 
182  */
183 static var_rc_t lookup_counter_var(var_t *ctx, void *my_ctx, 
184           const char *var_ptr, int var_len, int var_inc, int var_index, 
185           const char **val_ptr, int *val_len, int *val_size)
186 {
187    char buf[MAXSTRING];
188    var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE;
189
190    if (var_len > (int)sizeof(buf) - 1) {
191        return VAR_ERR_OUT_OF_MEMORY;
192    }
193    memcpy(buf, var_ptr, var_len);
194    buf[var_len] = 0;
195    LockRes();
196    for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
197       if (strcmp(counter->hdr.name, buf) == 0) {
198          Dmsg2(100, "Counter=%s val=%d\n", buf, counter->CurrentValue);
199          bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
200          *val_ptr = bstrdup(buf);
201          *val_len = strlen(buf);
202          *val_size = *val_len;
203          if (var_inc && counter->Catalog) {
204             COUNTER_DBR cr;
205             JCR *jcr = (JCR *)my_ctx;
206             memset(&cr, 0, sizeof(cr));
207             bstrncpy(cr.Counter, counter->hdr.name, sizeof(cr.Counter));
208             cr.MinValue = counter->MinValue;
209             cr.MaxValue = counter->MaxValue;
210             if (counter->CurrentValue == counter->MaxValue) {
211                counter->CurrentValue = counter->MinValue;
212             } else {
213                counter->CurrentValue++;
214             }
215             cr.CurrentValue = counter->CurrentValue;
216             Dmsg1(100, "New value=%d\n", cr.CurrentValue);
217             if (counter->WrapCounter) {
218                bstrncpy(cr.WrapCounter, counter->WrapCounter->hdr.name, sizeof(cr.WrapCounter));
219             } else {
220                cr.WrapCounter[0] = 0;
221             }
222             if (!db_update_counter_record(jcr, jcr->db, &cr)) {
223                Jmsg(jcr, M_ERROR, 0, _("Count not update counter %s: ERR=%s\n"),
224                   counter->hdr.name, db_strerror(jcr->db));
225             }
226          }  
227          stat = VAR_OK;
228          break;
229       }
230    }
231    UnlockRes();
232    return stat;
233 }
234
235
236 /*
237  * Called here to look up a variable   
238  */
239 static var_rc_t lookup_var(var_t *ctx, void *my_ctx, 
240           const char *var_ptr, int var_len, int var_inc, int var_index, 
241           const char **val_ptr, int *val_len, int *val_size)
242 {
243    char buf[MAXSTRING], *val, *p, *v;
244    var_rc_t stat;
245    int count;
246
247    if ((stat = lookup_built_in_var(ctx, my_ctx, var_ptr, var_len, var_index,
248         val_ptr, val_len, val_size)) == VAR_OK) {
249       return VAR_OK;
250    }
251
252    if ((stat = lookup_counter_var(ctx, my_ctx, var_ptr, var_len, var_inc, var_index,
253         val_ptr, val_len, val_size)) == VAR_OK) {
254       return VAR_OK;
255    }
256
257    /* Look in environment */
258    if (var_len > (int)sizeof(buf) - 1) {
259        return VAR_ERR_OUT_OF_MEMORY;
260    }
261    memcpy(buf, var_ptr, var_len + 1);
262    buf[var_len] = 0;
263    Dmsg1(100, "Var=%s\n", buf);
264
265    if ((val = getenv(buf)) == NULL) {
266        return VAR_ERR_UNDEFINED_VARIABLE;
267    }
268    if (var_index == 0) {
269       *val_ptr = val;
270       *val_len = strlen(val);
271       *val_size = 0;
272       return VAR_OK;
273    }
274    /* He wants to index the "array" */
275    count = 0;
276    /* Find the size of the "array"                           
277     *   each element is separated by a |  
278     */
279    for (p = val; *p; p++) {
280       if (*p == '|') {
281          count++;
282       }
283    }
284    count++;
285    Dmsg3(100, "For %s, reqest index=%d have=%d\n",
286       buf, var_index, count);
287    if (var_index < 0 || var_index > count) {
288       return VAR_ERR_SUBMATCH_OUT_OF_RANGE;
289    }
290    /* Now find the particular item (var_index) he wants */
291    count = 1;
292    for (p=val; *p; ) {
293       if (*p == '|') {
294          if (count < var_index) {
295             val = ++p;
296             count++;
297             continue;
298          }
299          break;
300       }
301       p++;
302    }
303    if (p-val > (int)sizeof(buf) - 1) {
304        return VAR_ERR_OUT_OF_MEMORY;
305    }
306    Dmsg2(100, "val=%s len=%d\n", val, p-val);
307    /* Make a copy of item, and pass it back */
308    v = (char *)malloc(p-val+1);
309    memcpy(v, val, p-val);
310    v[p-val] = 0;
311    *val_ptr = v;
312    *val_len = p-val;
313    *val_size = p-val;
314    Dmsg1(100, "v=%s\n", v);
315    return VAR_OK;
316 }
317
318 /*
319  * Called here to do a special operation on a variable
320  *   op_ptr  points to the special operation code (not EOS terminated)
321  *   arg_ptr points to argument to special op code
322  *   val_ptr points to the value string
323  *   out_ptr points to string to be returned
324  */
325 static var_rc_t operate_var(var_t *var, void *my_ctx, 
326           const char *op_ptr, int op_len, 
327           const char *arg_ptr, int arg_len,
328           const char *val_ptr, int val_len, 
329           char **out_ptr, int *out_len, int *out_size)
330 {
331    var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION;
332    Dmsg0(100, "Enter operate_var\n");
333    if (!val_ptr) {
334       *out_size = 0;
335       return stat;
336    }
337    if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) {
338       char buf[MAXSTRING];
339       if (val_len > (int)sizeof(buf) - 1) {
340           return VAR_ERR_OUT_OF_MEMORY;
341       }
342       memcpy(buf, arg_ptr, arg_len);
343       buf[arg_len] = 0;
344       Dmsg1(100, "Arg=%s\n", buf);
345       memcpy(buf, val_ptr, val_len);
346       buf[val_len] = 0;   
347       Dmsg1(100, "Val=%s\n", buf);
348       LockRes();
349       for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
350          if (strcmp(counter->hdr.name, buf) == 0) {
351             Dmsg2(100, "counter=%s val=%s\n", counter->hdr.name, buf);
352             break;
353          }
354       }
355       UnlockRes();
356       return stat;
357    }
358    *out_size = 0;
359    return stat;
360 }
361
362
363 /* 
364  * Expand an input line and return it.
365  *
366  *  Returns: 0 on failure
367  *           1 on success and exp has expanded input
368  */
369 int variable_expansion(JCR *jcr, char *inp, POOLMEM **exp)
370 {
371    var_t *var_ctx;
372    var_rc_t stat;
373    char *outp;
374    int in_len, out_len;
375    int rtn_stat = 0;
376
377    in_len = strlen(inp);
378    outp = NULL;
379    out_len = 0;
380
381    /* create context */
382    if ((stat = var_create(&var_ctx)) != VAR_OK) {
383        Jmsg(jcr, M_ERROR, 0, _("Cannot create var context: ERR=%s\n"), var_strerror(var_ctx, stat));
384        goto bail_out;
385    }
386    /* define callback */
387    if ((stat = var_config(var_ctx, VAR_CONFIG_CB_VALUE, lookup_var, (void *)jcr)) != VAR_OK) {
388        Jmsg(jcr, M_ERROR, 0, _("Cannot set var callback: ERR=%s\n"), var_strerror(var_ctx, stat));
389        goto bail_out;
390    }
391
392    /* define special operations */
393    if ((stat = var_config(var_ctx, VAR_CONFIG_CB_OPERATION, operate_var, (void *)jcr)) != VAR_OK) {
394        Jmsg(jcr, M_ERROR, 0, _("Cannot set var operate: ERR=%s\n"), var_strerror(var_ctx, stat));
395        goto bail_out;
396    }
397
398    /* unescape in place */
399    if ((stat = var_unescape(var_ctx, inp, in_len, inp, in_len+1, 0)) != VAR_OK) {
400        Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
401        goto bail_out;
402    }
403
404    in_len = strlen(inp);
405
406    /* expand variables */
407    if ((stat = var_expand(var_ctx, inp, in_len, &outp, &out_len, 1)) != VAR_OK) {
408        Jmsg(jcr, M_ERROR, 0, _("Cannot expand LabelFormat \"%s\": ERR=%s\n"), 
409           inp, var_strerror(var_ctx, stat));
410        goto bail_out;
411    }
412
413    /* unescape once more in place */
414    if ((stat = var_unescape(var_ctx, outp, out_len, outp, out_len+1, 1)) != VAR_OK) {
415        Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
416        goto bail_out;
417    }
418
419    pm_strcpy(exp, outp);
420
421    rtn_stat = 1;  
422
423 bail_out:
424    /* destroy expansion context */
425    if ((stat = var_destroy(var_ctx)) != VAR_OK) {
426        Jmsg(jcr, M_ERROR, 0, _("Cannot destroy var context: ERR=%s\n"), var_strerror(var_ctx, stat));
427    }
428    if (outp) {
429       free(outp);
430    }
431    return rtn_stat;
432 }