3 * Bacula Director -- expand.c -- does variable expansion
4 * in particular for the LabelFormat specification.
6 * Kern Sibbald, June MMIII
11 Bacula® - The Network Backup Solution
13 Copyright (C) 2003-2014 Free Software Foundation Europe e.V.
15 The main author of Bacula is Kern Sibbald, with contributions from many
16 others, a complete list can be found in the file AUTHORS.
18 You may use this file and others of this release according to the
19 license defined in the LICENSE file, which includes the Affero General
20 Public License, v3.0 ("AGPLv3") and some additional permissions and
21 terms pursuant to its AGPLv3 Section 7.
23 Bacula® is a registered trademark of Kern Sibbald.
31 static int date_item(JCR *jcr, int code,
32 const char **val_ptr, int *val_len, int *val_size)
35 time_t now = time(NULL);
36 (void)localtime_r(&now, &tm);
42 val = tm.tm_year + 1900;
59 case 7: /* Week day */
63 bsnprintf(buf, sizeof(buf), "%d", val);
64 *val_ptr = bstrdup(buf);
65 *val_len = strlen(buf);
66 *val_size = *val_len + 1;
70 static int job_item(JCR *jcr, int code,
71 const char **val_ptr, int *val_len, int *val_size)
73 const char *str = " ";
78 str = jcr->job->name();
80 case 2: /* Director's name */
84 str = job_level_to_str(jcr->getJobLevel());
87 str = job_type_to_str(jcr->getJobType());
90 bsnprintf(buf, sizeof(buf), "%d", jcr->JobId);
94 str = jcr->client->name();
100 bsnprintf(buf, sizeof(buf), "%d", jcr->NumVols);
104 str = jcr->pool->name();
106 case 9: /* Storage */
108 str = jcr->wstore->name();
110 str = jcr->rstore->name();
113 case 10: /* Catalog */
114 str = jcr->catalog->name();
116 case 11: /* MediaType */
118 str = jcr->wstore->media_type;
120 str = jcr->rstore->media_type;
123 case 12: /* JobName */
127 *val_ptr = bstrdup(str);
128 *val_len = strlen(str);
129 *val_size = *val_len + 1;
133 struct s_built_in_vars {const char *var_name; int code; int (*func)(JCR *jcr, int code,
134 const char **val_ptr, int *val_len, int *val_size);};
137 * Table of build in variables
139 static struct s_built_in_vars built_in_vars[] = {
140 { NT_("Year"), 1, date_item},
141 { NT_("Month"), 2, date_item},
142 { NT_("Day"), 3, date_item},
143 { NT_("Hour"), 4, date_item},
144 { NT_("Minute"), 5, date_item},
145 { NT_("Second"), 6, date_item},
146 { NT_("WeekDay"), 7, date_item},
148 { NT_("Job"), 1, job_item},
149 { NT_("Dir"), 2, job_item},
150 { NT_("Level"), 3, job_item},
151 { NT_("Type"), 4, job_item},
152 { NT_("JobId"), 5, job_item},
153 { NT_("Client"), 6, job_item},
154 { NT_("NumVols"), 7, job_item},
155 { NT_("Pool"), 8, job_item},
156 { NT_("Storage"), 9, job_item},
157 { NT_("Catalog"), 10, job_item},
158 { NT_("MediaType"), 11, job_item},
159 { NT_("JobName"), 12, job_item},
166 * Search the table of built-in variables, and if found,
167 * call the appropriate subroutine to do the work.
169 static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx,
170 const char *var_ptr, int var_len, int var_index,
171 const char **val_ptr, int *val_len, int *val_size)
173 JCR *jcr = (JCR *)my_ctx;
176 for (int i=0; _(built_in_vars[i].var_name); i++) {
177 if (strncmp(_(built_in_vars[i].var_name), var_ptr, var_len) == 0) {
178 stat = (*built_in_vars[i].func)(jcr, built_in_vars[i].code,
179 val_ptr, val_len, val_size);
186 return VAR_ERR_UNDEFINED_VARIABLE;
191 * Search counter variables
193 static var_rc_t lookup_counter_var(var_t *ctx, void *my_ctx,
194 const char *var_ptr, int var_len, int var_inc, int var_index,
195 const char **val_ptr, int *val_len, int *val_size)
198 var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE;
200 if (var_len > (int)sizeof(buf) - 1) {
201 return VAR_ERR_OUT_OF_MEMORY;
203 memcpy(buf, var_ptr, var_len);
206 for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
207 if (strcmp(counter->name(), buf) == 0) {
208 Dmsg2(100, "Counter=%s val=%d\n", buf, counter->CurrentValue);
209 /* -1 => return size of array */
210 if (var_index == -1) {
211 bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
212 *val_len = bsnprintf(buf, sizeof(buf), "%d", strlen(buf));
214 *val_size = 0; /* don't try to free val_ptr */
217 bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
218 *val_ptr = bstrdup(buf);
219 *val_len = strlen(buf);
220 *val_size = *val_len + 1;
222 if (var_inc) { /* increment the variable? */
223 if (counter->CurrentValue == counter->MaxValue) {
224 counter->CurrentValue = counter->MinValue;
226 counter->CurrentValue++;
228 if (counter->Catalog) { /* update catalog if need be */
230 JCR *jcr = (JCR *)my_ctx;
231 memset(&cr, 0, sizeof(cr));
232 bstrncpy(cr.Counter, counter->name(), sizeof(cr.Counter));
233 cr.MinValue = counter->MinValue;
234 cr.MaxValue = counter->MaxValue;
235 cr.CurrentValue = counter->CurrentValue;
236 Dmsg1(100, "New value=%d\n", cr.CurrentValue);
237 if (counter->WrapCounter) {
238 bstrncpy(cr.WrapCounter, counter->WrapCounter->name(), sizeof(cr.WrapCounter));
240 cr.WrapCounter[0] = 0;
242 if (!db_update_counter_record(jcr, jcr->db, &cr)) {
243 Jmsg(jcr, M_ERROR, 0, _("Count not update counter %s: ERR=%s\n"),
244 counter->name(), db_strerror(jcr->db));
258 * Called here from "core" expand code to look up a variable
260 static var_rc_t lookup_var(var_t *ctx, void *my_ctx,
261 const char *var_ptr, int var_len, int var_inc, int var_index,
262 const char **val_ptr, int *val_len, int *val_size)
264 char buf[MAXSTRING], *val, *p, *v;
268 /* Note, if val_size > 0 and val_ptr!=NULL, the core code will free() it */
269 if ((stat = lookup_built_in_var(ctx, my_ctx, var_ptr, var_len, var_index,
270 val_ptr, val_len, val_size)) == VAR_OK) {
274 if ((stat = lookup_counter_var(ctx, my_ctx, var_ptr, var_len, var_inc, var_index,
275 val_ptr, val_len, val_size)) == VAR_OK) {
279 /* Look in environment */
280 if (var_len > (int)sizeof(buf) - 1) {
281 return VAR_ERR_OUT_OF_MEMORY;
283 memcpy(buf, var_ptr, var_len + 1);
285 Dmsg1(100, "Var=%s\n", buf);
287 if ((val = getenv(buf)) == NULL) {
288 return VAR_ERR_UNDEFINED_VARIABLE;
290 /* He wants to index the "array" */
292 /* Find the size of the "array"
293 * each element is separated by a |
295 for (p = val; *p; p++) {
300 Dmsg3(100, "For %s, reqest index=%d have=%d\n",
301 buf, var_index, count);
303 /* -1 => return size of array */
304 if (var_index == -1) {
306 if (count == 1) { /* if not array */
307 len = strlen(val); /* return length of string */
309 len = count; /* else return # array items */
311 *val_len = bsnprintf(buf, sizeof(buf), "%d", len);
313 *val_size = 0; /* don't try to free val_ptr */
318 if (var_index < -1 || var_index > --count) {
319 // return VAR_ERR_SUBMATCH_OUT_OF_RANGE;
320 return VAR_ERR_UNDEFINED_VARIABLE;
322 /* Now find the particular item (var_index) he wants */
326 if (count < var_index) {
335 if (p-val > (int)sizeof(buf) - 1) {
336 return VAR_ERR_OUT_OF_MEMORY;
338 Dmsg2(100, "val=%s len=%d\n", val, p-val);
339 /* Make a copy of item, and pass it back */
340 v = (char *)malloc(p-val+1);
341 memcpy(v, val, p-val);
346 Dmsg1(100, "v=%s\n", v);
351 * Called here to do a special operation on a variable
352 * op_ptr points to the special operation code (not EOS terminated)
353 * arg_ptr points to argument to special op code
354 * val_ptr points to the value string
355 * out_ptr points to string to be returned
357 static var_rc_t operate_var(var_t *var, void *my_ctx,
358 const char *op_ptr, int op_len,
359 const char *arg_ptr, int arg_len,
360 const char *val_ptr, int val_len,
361 char **out_ptr, int *out_len, int *out_size)
363 var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION;
364 Dmsg0(100, "Enter operate_var\n");
369 if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) {
371 if (val_len > (int)sizeof(buf) - 1) {
372 return VAR_ERR_OUT_OF_MEMORY;
374 memcpy(buf, arg_ptr, arg_len);
376 Dmsg1(100, "Arg=%s\n", buf);
377 memcpy(buf, val_ptr, val_len);
379 Dmsg1(100, "Val=%s\n", buf);
381 for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
382 if (strcmp(counter->name(), buf) == 0) {
383 Dmsg2(100, "counter=%s val=%s\n", counter->name(), buf);
396 * Expand an input line and return it.
398 * Returns: 0 on failure
399 * 1 on success and exp has expanded input
401 int variable_expansion(JCR *jcr, char *inp, POOLMEM **exp)
409 in_len = strlen(inp);
414 if ((stat = var_create(&var_ctx)) != VAR_OK) {
415 Jmsg(jcr, M_ERROR, 0, _("Cannot create var context: ERR=%s\n"), var_strerror(var_ctx, stat));
418 /* define callback */
419 if ((stat = var_config(var_ctx, VAR_CONFIG_CB_VALUE, lookup_var, (void *)jcr)) != VAR_OK) {
420 Jmsg(jcr, M_ERROR, 0, _("Cannot set var callback: ERR=%s\n"), var_strerror(var_ctx, stat));
424 /* define special operations */
425 if ((stat = var_config(var_ctx, VAR_CONFIG_CB_OPERATION, operate_var, (void *)jcr)) != VAR_OK) {
426 Jmsg(jcr, M_ERROR, 0, _("Cannot set var operate: ERR=%s\n"), var_strerror(var_ctx, stat));
430 /* unescape in place */
431 if ((stat = var_unescape(var_ctx, inp, in_len, inp, in_len+1, 0)) != VAR_OK) {
432 Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
436 in_len = strlen(inp);
438 /* expand variables */
439 if ((stat = var_expand(var_ctx, inp, in_len, &outp, &out_len, 0)) != VAR_OK) {
440 Jmsg(jcr, M_ERROR, 0, _("Cannot expand expression \"%s\": ERR=%s\n"),
441 inp, var_strerror(var_ctx, stat));
445 /* unescape once more in place */
446 if ((stat = var_unescape(var_ctx, outp, out_len, outp, out_len+1, 1)) != VAR_OK) {
447 Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
451 pm_strcpy(exp, outp);
456 /* destroy expansion context */
457 if ((stat = var_destroy(var_ctx)) != VAR_OK) {
458 Jmsg(jcr, M_ERROR, 0, _("Cannot destroy var context: ERR=%s\n"), var_strerror(var_ctx, stat));