3 * Bacula Director -- expand.c -- does variable expansion
4 * in particular for the LabelFormat specification.
6 * Kern Sibbald, June MMIII
11 Copyright (C) 2003-2004 Kern Sibbald and John Walker
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.
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.
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,
35 static int date_item(JCR *jcr, int code,
36 const char **val_ptr, int *val_len, int *val_size)
39 time_t now = time(NULL);
40 localtime_r(&now, &tm);
46 val = tm.tm_year + 1900;
63 case 7: /* Week day */
67 bsnprintf(buf, sizeof(buf), "%d", val);
68 *val_ptr = bstrdup(buf);
69 *val_len = strlen(buf);
70 *val_size = *val_len + 1;
74 static int job_item(JCR *jcr, int code,
75 const char **val_ptr, int *val_len, int *val_size)
77 const char *str = " ";
82 str = jcr->job->hdr.name;
84 case 2: /* Director's name */
88 str = job_level_to_str(jcr->JobLevel);
91 str = job_type_to_str(jcr->JobType);
94 bsnprintf(buf, sizeof(buf), "%d", jcr->JobId);
98 str = jcr->client->hdr.name;
103 case 7: /* NumVols */
104 bsnprintf(buf, sizeof(buf), "%d", jcr->NumVols);
108 str = jcr->pool->hdr.name;
110 case 9: /* Storage */
111 str = jcr->store->hdr.name;
113 case 10: /* Catalog */
114 str = jcr->catalog->hdr.name;
116 case 11: /* MediaType */
117 str = jcr->store->media_type;
119 case 12: /* JobName */
123 *val_ptr = bstrdup(str);
124 *val_len = strlen(str);
125 *val_size = *val_len + 1;
129 struct s_built_in_vars {const char *var_name; int code; int (*func)(JCR *jcr, int code,
130 const char **val_ptr, int *val_len, int *val_size);};
133 * Table of build in variables
135 static struct s_built_in_vars built_in_vars[] = {
136 { NT_("Year"), 1, date_item},
137 { NT_("Month"), 2, date_item},
138 { NT_("Day"), 3, date_item},
139 { NT_("Hour"), 4, date_item},
140 { NT_("Minute"), 5, date_item},
141 { NT_("Second"), 6, date_item},
142 { NT_("WeekDay"), 7, date_item},
144 { NT_("Job"), 1, job_item},
145 { NT_("Dir"), 2, job_item},
146 { NT_("Level"), 3, job_item},
147 { NT_("Type"), 4, job_item},
148 { NT_("JobId"), 5, job_item},
149 { NT_("Client"), 6, job_item},
150 { NT_("NumVols"), 7, job_item},
151 { NT_("Pool"), 8, job_item},
152 { NT_("Storage"), 9, job_item},
153 { NT_("Catalog"), 10, job_item},
154 { NT_("MediaType"), 11, job_item},
155 { NT_("JobName"), 12, job_item},
162 * Search the table of built-in variables, and if found,
163 * call the appropriate subroutine to do the work.
165 static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx,
166 const char *var_ptr, int var_len, int var_index,
167 const char **val_ptr, int *val_len, int *val_size)
169 JCR *jcr = (JCR *)my_ctx;
172 for (int i=0; _(built_in_vars[i].var_name); i++) {
173 if (strncmp(_(built_in_vars[i].var_name), var_ptr, var_len) == 0) {
174 stat = (*built_in_vars[i].func)(jcr, built_in_vars[i].code,
175 val_ptr, val_len, val_size);
182 return VAR_ERR_UNDEFINED_VARIABLE;
187 * Search counter variables
189 static var_rc_t lookup_counter_var(var_t *ctx, void *my_ctx,
190 const char *var_ptr, int var_len, int var_inc, int var_index,
191 const char **val_ptr, int *val_len, int *val_size)
194 var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE;
196 if (var_len > (int)sizeof(buf) - 1) {
197 return VAR_ERR_OUT_OF_MEMORY;
199 memcpy(buf, var_ptr, var_len);
202 for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
203 if (strcmp(counter->hdr.name, buf) == 0) {
204 Dmsg2(100, "Counter=%s val=%d\n", buf, counter->CurrentValue);
205 /* -1 => return size of array */
206 if (var_index == -1) {
207 bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
208 *val_len = bsnprintf(buf, sizeof(buf), "%d", strlen(buf));
210 *val_size = 0; /* don't try to free val_ptr */
213 bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
214 *val_ptr = bstrdup(buf);
215 *val_len = strlen(buf);
216 *val_size = *val_len + 1;
218 if (var_inc) { /* increment the variable? */
219 if (counter->CurrentValue == counter->MaxValue) {
220 counter->CurrentValue = counter->MinValue;
222 counter->CurrentValue++;
224 if (counter->Catalog) { /* update catalog if need be */
226 JCR *jcr = (JCR *)my_ctx;
227 memset(&cr, 0, sizeof(cr));
228 bstrncpy(cr.Counter, counter->hdr.name, sizeof(cr.Counter));
229 cr.MinValue = counter->MinValue;
230 cr.MaxValue = counter->MaxValue;
231 cr.CurrentValue = counter->CurrentValue;
232 Dmsg1(100, "New value=%d\n", cr.CurrentValue);
233 if (counter->WrapCounter) {
234 bstrncpy(cr.WrapCounter, counter->WrapCounter->hdr.name, sizeof(cr.WrapCounter));
236 cr.WrapCounter[0] = 0;
238 if (!db_update_counter_record(jcr, jcr->db, &cr)) {
239 Jmsg(jcr, M_ERROR, 0, _("Count not update counter %s: ERR=%s\n"),
240 counter->hdr.name, db_strerror(jcr->db));
254 * Called here from "core" expand code to look up a variable
256 static var_rc_t lookup_var(var_t *ctx, void *my_ctx,
257 const char *var_ptr, int var_len, int var_inc, int var_index,
258 const char **val_ptr, int *val_len, int *val_size)
260 char buf[MAXSTRING], *val, *p, *v;
264 /* Note, if val_size > 0 and val_ptr!=NULL, the core code will free() it */
265 if ((stat = lookup_built_in_var(ctx, my_ctx, var_ptr, var_len, var_index,
266 val_ptr, val_len, val_size)) == VAR_OK) {
270 if ((stat = lookup_counter_var(ctx, my_ctx, var_ptr, var_len, var_inc, var_index,
271 val_ptr, val_len, val_size)) == VAR_OK) {
275 /* Look in environment */
276 if (var_len > (int)sizeof(buf) - 1) {
277 return VAR_ERR_OUT_OF_MEMORY;
279 memcpy(buf, var_ptr, var_len + 1);
281 Dmsg1(100, "Var=%s\n", buf);
283 if ((val = getenv(buf)) == NULL) {
284 return VAR_ERR_UNDEFINED_VARIABLE;
286 /* He wants to index the "array" */
288 /* Find the size of the "array"
289 * each element is separated by a |
291 for (p = val; *p; p++) {
296 Dmsg3(100, "For %s, reqest index=%d have=%d\n",
297 buf, var_index, count);
299 /* -1 => return size of array */
300 if (var_index == -1) {
302 if (count == 1) { /* if not array */
303 len = strlen(val); /* return length of string */
305 len = count; /* else return # array items */
307 *val_len = bsnprintf(buf, sizeof(buf), "%d", len);
309 *val_size = 0; /* don't try to free val_ptr */
314 if (var_index < -1 || var_index > --count) {
315 // return VAR_ERR_SUBMATCH_OUT_OF_RANGE;
316 return VAR_ERR_UNDEFINED_VARIABLE;
318 /* Now find the particular item (var_index) he wants */
322 if (count < var_index) {
331 if (p-val > (int)sizeof(buf) - 1) {
332 return VAR_ERR_OUT_OF_MEMORY;
334 Dmsg2(100, "val=%s len=%d\n", val, p-val);
335 /* Make a copy of item, and pass it back */
336 v = (char *)malloc(p-val+1);
337 memcpy(v, val, p-val);
342 Dmsg1(100, "v=%s\n", v);
347 * Called here to do a special operation on a variable
348 * op_ptr points to the special operation code (not EOS terminated)
349 * arg_ptr points to argument to special op code
350 * val_ptr points to the value string
351 * out_ptr points to string to be returned
353 static var_rc_t operate_var(var_t *var, void *my_ctx,
354 const char *op_ptr, int op_len,
355 const char *arg_ptr, int arg_len,
356 const char *val_ptr, int val_len,
357 char **out_ptr, int *out_len, int *out_size)
359 var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION;
360 Dmsg0(100, "Enter operate_var\n");
365 if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) {
367 if (val_len > (int)sizeof(buf) - 1) {
368 return VAR_ERR_OUT_OF_MEMORY;
370 memcpy(buf, arg_ptr, arg_len);
372 Dmsg1(100, "Arg=%s\n", buf);
373 memcpy(buf, val_ptr, val_len);
375 Dmsg1(100, "Val=%s\n", buf);
377 for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
378 if (strcmp(counter->hdr.name, buf) == 0) {
379 Dmsg2(100, "counter=%s val=%s\n", counter->hdr.name, buf);
392 * Expand an input line and return it.
394 * Returns: 0 on failure
395 * 1 on success and exp has expanded input
397 int variable_expansion(JCR *jcr, char *inp, POOLMEM **exp)
405 in_len = strlen(inp);
410 if ((stat = var_create(&var_ctx)) != VAR_OK) {
411 Jmsg(jcr, M_ERROR, 0, _("Cannot create var context: ERR=%s\n"), var_strerror(var_ctx, stat));
414 /* define callback */
415 if ((stat = var_config(var_ctx, VAR_CONFIG_CB_VALUE, lookup_var, (void *)jcr)) != VAR_OK) {
416 Jmsg(jcr, M_ERROR, 0, _("Cannot set var callback: ERR=%s\n"), var_strerror(var_ctx, stat));
420 /* define special operations */
421 if ((stat = var_config(var_ctx, VAR_CONFIG_CB_OPERATION, operate_var, (void *)jcr)) != VAR_OK) {
422 Jmsg(jcr, M_ERROR, 0, _("Cannot set var operate: ERR=%s\n"), var_strerror(var_ctx, stat));
426 /* unescape in place */
427 if ((stat = var_unescape(var_ctx, inp, in_len, inp, in_len+1, 0)) != VAR_OK) {
428 Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
432 in_len = strlen(inp);
434 /* expand variables */
435 if ((stat = var_expand(var_ctx, inp, in_len, &outp, &out_len, 0)) != VAR_OK) {
436 Jmsg(jcr, M_ERROR, 0, _("Cannot expand expression \"%s\": ERR=%s\n"),
437 inp, var_strerror(var_ctx, stat));
441 /* unescape once more in place */
442 if ((stat = var_unescape(var_ctx, outp, out_len, outp, out_len+1, 1)) != VAR_OK) {
443 Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
447 pm_strcpy(exp, outp);
452 /* destroy expansion context */
453 if ((stat = var_destroy(var_ctx)) != VAR_OK) {
454 Jmsg(jcr, M_ERROR, 0, _("Cannot destroy var context: ERR=%s\n"), var_strerror(var_ctx, stat));