2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula Director -- expand.c -- does variable expansion
22 * in particular for the LabelFormat specification.
24 * Kern Sibbald, June MMIII
33 static int date_item(JCR *jcr, int code,
34 const char **val_ptr, int *val_len, int *val_size)
37 time_t now = time(NULL);
38 (void)localtime_r(&now, &tm);
44 val = tm.tm_year + 1900;
61 case 7: /* Week day */
65 bsnprintf(buf, sizeof(buf), "%d", val);
66 *val_ptr = bstrdup(buf);
67 *val_len = strlen(buf);
68 *val_size = *val_len + 1;
72 static int job_item(JCR *jcr, int code,
73 const char **val_ptr, int *val_len, int *val_size)
75 const char *str = " ";
80 str = jcr->job->name();
82 case 2: /* Director's name */
86 str = job_level_to_str(jcr->getJobLevel());
89 str = job_type_to_str(jcr->getJobType());
92 bsnprintf(buf, sizeof(buf), "%d", jcr->JobId);
96 str = jcr->client->name();
101 case 7: /* NumVols */
102 bsnprintf(buf, sizeof(buf), "%d", jcr->NumVols);
106 str = jcr->pool->name();
108 case 9: /* Storage */
110 str = jcr->wstore->name();
112 str = jcr->rstore->name();
115 case 10: /* Catalog */
116 str = jcr->catalog->name();
118 case 11: /* MediaType */
120 str = jcr->wstore->media_type;
122 str = jcr->rstore->media_type;
125 case 12: /* JobName */
129 *val_ptr = bstrdup(str);
130 *val_len = strlen(str);
131 *val_size = *val_len + 1;
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);};
139 * Table of build in variables
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},
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},
168 * Search the table of built-in variables, and if found,
169 * call the appropriate subroutine to do the work.
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)
175 JCR *jcr = (JCR *)my_ctx;
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);
188 return VAR_ERR_UNDEFINED_VARIABLE;
193 * Search counter variables
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)
200 var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE;
202 if (var_len > (int)sizeof(buf) - 1) {
203 return VAR_ERR_OUT_OF_MEMORY;
205 memcpy(buf, var_ptr, var_len);
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));
216 *val_size = 0; /* don't try to free val_ptr */
219 bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
220 *val_ptr = bstrdup(buf);
221 *val_len = strlen(buf);
222 *val_size = *val_len + 1;
224 if (var_inc) { /* increment the variable? */
225 if (counter->CurrentValue == counter->MaxValue) {
226 counter->CurrentValue = counter->MinValue;
228 counter->CurrentValue++;
230 if (counter->Catalog) { /* update catalog if need be */
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));
242 cr.WrapCounter[0] = 0;
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));
260 * Called here from "core" expand code to look up a variable
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)
266 char buf[MAXSTRING], *val, *p, *v;
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) {
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) {
281 /* Look in environment */
282 if (var_len > (int)sizeof(buf) - 1) {
283 return VAR_ERR_OUT_OF_MEMORY;
285 memcpy(buf, var_ptr, var_len + 1);
287 Dmsg1(100, "Var=%s\n", buf);
289 if ((val = getenv(buf)) == NULL) {
290 return VAR_ERR_UNDEFINED_VARIABLE;
292 /* He wants to index the "array" */
294 /* Find the size of the "array"
295 * each element is separated by a |
297 for (p = val; *p; p++) {
302 Dmsg3(100, "For %s, reqest index=%d have=%d\n",
303 buf, var_index, count);
305 /* -1 => return size of array */
306 if (var_index == -1) {
308 if (count == 1) { /* if not array */
309 len = strlen(val); /* return length of string */
311 len = count; /* else return # array items */
313 *val_len = bsnprintf(buf, sizeof(buf), "%d", len);
315 *val_size = 0; /* don't try to free val_ptr */
320 if (var_index < -1 || var_index > --count) {
321 // return VAR_ERR_SUBMATCH_OUT_OF_RANGE;
322 return VAR_ERR_UNDEFINED_VARIABLE;
324 /* Now find the particular item (var_index) he wants */
328 if (count < var_index) {
337 if (p-val > (int)sizeof(buf) - 1) {
338 return VAR_ERR_OUT_OF_MEMORY;
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);
348 Dmsg1(100, "v=%s\n", v);
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
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)
365 var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION;
366 Dmsg0(100, "Enter operate_var\n");
371 if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) {
373 if (val_len > (int)sizeof(buf) - 1) {
374 return VAR_ERR_OUT_OF_MEMORY;
376 memcpy(buf, arg_ptr, arg_len);
378 Dmsg1(100, "Arg=%s\n", buf);
379 memcpy(buf, val_ptr, val_len);
381 Dmsg1(100, "Val=%s\n", buf);
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);
398 * Expand an input line and return it.
400 * Returns: 0 on failure
401 * 1 on success and exp has expanded input
403 int variable_expansion(JCR *jcr, char *inp, POOLMEM **exp)
411 in_len = strlen(inp);
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));
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));
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));
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));
438 in_len = strlen(inp);
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));
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));
453 pm_strcpy(exp, outp);
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));