2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 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
32 static int date_item(JCR *jcr, int code,
33 const char **val_ptr, int *val_len, int *val_size)
36 time_t now = time(NULL);
37 (void)localtime_r(&now, &tm);
43 val = tm.tm_year + 1900;
60 case 7: /* Week day */
64 bsnprintf(buf, sizeof(buf), "%d", val);
65 *val_ptr = bstrdup(buf);
66 *val_len = strlen(buf);
67 *val_size = *val_len + 1;
71 static int job_item(JCR *jcr, int code,
72 const char **val_ptr, int *val_len, int *val_size)
74 const char *str = " ";
79 str = jcr->job->name();
81 case 2: /* Director's name */
85 str = job_level_to_str(jcr->getJobLevel());
88 str = job_type_to_str(jcr->getJobType());
91 bsnprintf(buf, sizeof(buf), "%d", jcr->JobId);
95 str = jcr->client->name();
100 case 7: /* NumVols */
101 bsnprintf(buf, sizeof(buf), "%d", jcr->NumVols);
105 str = jcr->pool->name();
107 case 9: /* Storage */
109 str = jcr->wstore->name();
111 str = jcr->rstore->name();
114 case 10: /* Catalog */
115 str = jcr->catalog->name();
117 case 11: /* MediaType */
119 str = jcr->wstore->media_type;
121 str = jcr->rstore->media_type;
124 case 12: /* JobName */
128 *val_ptr = bstrdup(str);
129 *val_len = strlen(str);
130 *val_size = *val_len + 1;
134 struct s_built_in_vars {const char *var_name; int code; int (*func)(JCR *jcr, int code,
135 const char **val_ptr, int *val_len, int *val_size);};
138 * Table of build in variables
140 static struct s_built_in_vars built_in_vars[] = {
141 { NT_("Year"), 1, date_item},
142 { NT_("Month"), 2, date_item},
143 { NT_("Day"), 3, date_item},
144 { NT_("Hour"), 4, date_item},
145 { NT_("Minute"), 5, date_item},
146 { NT_("Second"), 6, date_item},
147 { NT_("WeekDay"), 7, date_item},
149 { NT_("Job"), 1, job_item},
150 { NT_("Dir"), 2, job_item},
151 { NT_("Level"), 3, job_item},
152 { NT_("Type"), 4, job_item},
153 { NT_("JobId"), 5, job_item},
154 { NT_("Client"), 6, job_item},
155 { NT_("NumVols"), 7, job_item},
156 { NT_("Pool"), 8, job_item},
157 { NT_("Storage"), 9, job_item},
158 { NT_("Catalog"), 10, job_item},
159 { NT_("MediaType"), 11, job_item},
160 { NT_("JobName"), 12, job_item},
167 * Search the table of built-in variables, and if found,
168 * call the appropriate subroutine to do the work.
170 static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx,
171 const char *var_ptr, int var_len, int var_index,
172 const char **val_ptr, int *val_len, int *val_size)
174 JCR *jcr = (JCR *)my_ctx;
177 for (int i=0; _(built_in_vars[i].var_name); i++) {
178 if (strncmp(_(built_in_vars[i].var_name), var_ptr, var_len) == 0) {
179 stat = (*built_in_vars[i].func)(jcr, built_in_vars[i].code,
180 val_ptr, val_len, val_size);
187 return VAR_ERR_UNDEFINED_VARIABLE;
192 * Search counter variables
194 static var_rc_t lookup_counter_var(var_t *ctx, void *my_ctx,
195 const char *var_ptr, int var_len, int var_inc, int var_index,
196 const char **val_ptr, int *val_len, int *val_size)
199 var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE;
201 if (var_len > (int)sizeof(buf) - 1) {
202 return VAR_ERR_OUT_OF_MEMORY;
204 memcpy(buf, var_ptr, var_len);
207 for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
208 if (strcmp(counter->name(), buf) == 0) {
209 Dmsg2(100, "Counter=%s val=%d\n", buf, counter->CurrentValue);
210 /* -1 => return size of array */
211 if (var_index == -1) {
212 bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
213 *val_len = bsnprintf(buf, sizeof(buf), "%d", strlen(buf));
215 *val_size = 0; /* don't try to free val_ptr */
218 bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
219 *val_ptr = bstrdup(buf);
220 *val_len = strlen(buf);
221 *val_size = *val_len + 1;
223 if (var_inc) { /* increment the variable? */
224 if (counter->CurrentValue == counter->MaxValue) {
225 counter->CurrentValue = counter->MinValue;
227 counter->CurrentValue++;
229 if (counter->Catalog) { /* update catalog if need be */
231 JCR *jcr = (JCR *)my_ctx;
232 memset(&cr, 0, sizeof(cr));
233 bstrncpy(cr.Counter, counter->name(), sizeof(cr.Counter));
234 cr.MinValue = counter->MinValue;
235 cr.MaxValue = counter->MaxValue;
236 cr.CurrentValue = counter->CurrentValue;
237 Dmsg1(100, "New value=%d\n", cr.CurrentValue);
238 if (counter->WrapCounter) {
239 bstrncpy(cr.WrapCounter, counter->WrapCounter->name(), sizeof(cr.WrapCounter));
241 cr.WrapCounter[0] = 0;
243 if (!db_update_counter_record(jcr, jcr->db, &cr)) {
244 Jmsg(jcr, M_ERROR, 0, _("Count not update counter %s: ERR=%s\n"),
245 counter->name(), db_strerror(jcr->db));
259 * Called here from "core" expand code to look up a variable
261 static var_rc_t lookup_var(var_t *ctx, void *my_ctx,
262 const char *var_ptr, int var_len, int var_inc, int var_index,
263 const char **val_ptr, int *val_len, int *val_size)
265 char buf[MAXSTRING], *val, *p, *v;
269 /* Note, if val_size > 0 and val_ptr!=NULL, the core code will free() it */
270 if ((stat = lookup_built_in_var(ctx, my_ctx, var_ptr, var_len, var_index,
271 val_ptr, val_len, val_size)) == VAR_OK) {
275 if ((stat = lookup_counter_var(ctx, my_ctx, var_ptr, var_len, var_inc, var_index,
276 val_ptr, val_len, val_size)) == VAR_OK) {
280 /* Look in environment */
281 if (var_len > (int)sizeof(buf) - 1) {
282 return VAR_ERR_OUT_OF_MEMORY;
284 memcpy(buf, var_ptr, var_len + 1);
286 Dmsg1(100, "Var=%s\n", buf);
288 if ((val = getenv(buf)) == NULL) {
289 return VAR_ERR_UNDEFINED_VARIABLE;
291 /* He wants to index the "array" */
293 /* Find the size of the "array"
294 * each element is separated by a |
296 for (p = val; *p; p++) {
301 Dmsg3(100, "For %s, reqest index=%d have=%d\n",
302 buf, var_index, count);
304 /* -1 => return size of array */
305 if (var_index == -1) {
307 if (count == 1) { /* if not array */
308 len = strlen(val); /* return length of string */
310 len = count; /* else return # array items */
312 *val_len = bsnprintf(buf, sizeof(buf), "%d", len);
314 *val_size = 0; /* don't try to free val_ptr */
319 if (var_index < -1 || var_index > --count) {
320 // return VAR_ERR_SUBMATCH_OUT_OF_RANGE;
321 return VAR_ERR_UNDEFINED_VARIABLE;
323 /* Now find the particular item (var_index) he wants */
327 if (count < var_index) {
336 if (p-val > (int)sizeof(buf) - 1) {
337 return VAR_ERR_OUT_OF_MEMORY;
339 Dmsg2(100, "val=%s len=%d\n", val, p-val);
340 /* Make a copy of item, and pass it back */
341 v = (char *)malloc(p-val+1);
342 memcpy(v, val, p-val);
347 Dmsg1(100, "v=%s\n", v);
352 * Called here to do a special operation on a variable
353 * op_ptr points to the special operation code (not EOS terminated)
354 * arg_ptr points to argument to special op code
355 * val_ptr points to the value string
356 * out_ptr points to string to be returned
358 static var_rc_t operate_var(var_t *var, void *my_ctx,
359 const char *op_ptr, int op_len,
360 const char *arg_ptr, int arg_len,
361 const char *val_ptr, int val_len,
362 char **out_ptr, int *out_len, int *out_size)
364 var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION;
365 Dmsg0(100, "Enter operate_var\n");
370 if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) {
372 if (val_len > (int)sizeof(buf) - 1) {
373 return VAR_ERR_OUT_OF_MEMORY;
375 memcpy(buf, arg_ptr, arg_len);
377 Dmsg1(100, "Arg=%s\n", buf);
378 memcpy(buf, val_ptr, val_len);
380 Dmsg1(100, "Val=%s\n", buf);
382 for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
383 if (strcmp(counter->name(), buf) == 0) {
384 Dmsg2(100, "counter=%s val=%s\n", counter->name(), buf);
397 * Expand an input line and return it.
399 * Returns: 0 on failure
400 * 1 on success and exp has expanded input
402 int variable_expansion(JCR *jcr, char *inp, POOLMEM **exp)
410 in_len = strlen(inp);
415 if ((stat = var_create(&var_ctx)) != VAR_OK) {
416 Jmsg(jcr, M_ERROR, 0, _("Cannot create var context: ERR=%s\n"), var_strerror(var_ctx, stat));
419 /* define callback */
420 if ((stat = var_config(var_ctx, VAR_CONFIG_CB_VALUE, lookup_var, (void *)jcr)) != VAR_OK) {
421 Jmsg(jcr, M_ERROR, 0, _("Cannot set var callback: ERR=%s\n"), var_strerror(var_ctx, stat));
425 /* define special operations */
426 if ((stat = var_config(var_ctx, VAR_CONFIG_CB_OPERATION, operate_var, (void *)jcr)) != VAR_OK) {
427 Jmsg(jcr, M_ERROR, 0, _("Cannot set var operate: ERR=%s\n"), var_strerror(var_ctx, stat));
431 /* unescape in place */
432 if ((stat = var_unescape(var_ctx, inp, in_len, inp, in_len+1, 0)) != VAR_OK) {
433 Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
437 in_len = strlen(inp);
439 /* expand variables */
440 if ((stat = var_expand(var_ctx, inp, in_len, &outp, &out_len, 0)) != VAR_OK) {
441 Jmsg(jcr, M_ERROR, 0, _("Cannot expand expression \"%s\": ERR=%s\n"),
442 inp, var_strerror(var_ctx, stat));
446 /* unescape once more in place */
447 if ((stat = var_unescape(var_ctx, outp, out_len, outp, out_len+1, 1)) != VAR_OK) {
448 Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
452 pm_strcpy(exp, outp);
457 /* destroy expansion context */
458 if ((stat = var_destroy(var_ctx)) != VAR_OK) {
459 Jmsg(jcr, M_ERROR, 0, _("Cannot destroy var context: ERR=%s\n"), var_strerror(var_ctx, stat));