3 * Bacula Director -- newvol.c -- creates new Volumes in
4 * catalog Media table from the LabelFormat specification.
6 * Kern Sibbald, May MMI
8 * This routine runs as a thread and must be thread reentrant.
10 * Basic tasks done here:
11 * If possible create a new Media entry
16 Copyright (C) 2000-2003 Kern Sibbald and John Walker
18 This program is free software; you can redistribute it and/or
19 modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation; either version 2 of
21 the License, or (at your option) any later version.
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 General Public License for more details.
28 You should have received a copy of the GNU General Public
29 License along with this program; if not, write to the Free
30 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
38 /* Forward referenced functions */
39 static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr);
40 static int perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr);
44 * Really crude automatic Volume name creation using
45 * LabelFormat. We assume that if this routine is being
46 * called the Volume will be labeled, so we set the LabelDate.
48 int newVolume(JCR *jcr, MEDIA_DBR *mr)
52 memset(&pr, 0, sizeof(pr));
54 /* See if we can create a new Volume */
56 pr.PoolId = jcr->PoolId;
57 if (db_get_pool_record(jcr, jcr->db, &pr) && pr.LabelFormat[0] &&
58 pr.LabelFormat[0] != '*') {
59 if (pr.MaxVols == 0 || pr.NumVols < pr.MaxVols) {
60 memset(mr, 0, sizeof(MEDIA_DBR));
61 set_pool_dbr_defaults_in_media_dbr(mr, &pr);
62 mr->LabelDate = time(NULL);
63 bstrncpy(mr->MediaType, jcr->store->media_type, sizeof(mr->MediaType));
64 /* Check for special characters */
65 if (is_volume_name_legal(NULL, pr.LabelFormat)) {
66 /* No special characters, so apply simple algorithm */
67 if (!create_simple_name(jcr, mr, &pr)) {
70 } else { /* try full substitution */
71 /* Found special characters, so try substitution */
72 if (!perform_full_name_substitution(jcr, mr, &pr)) {
75 if (!is_volume_name_legal(NULL, mr->VolumeName)) {
76 Jmsg(jcr, M_ERROR, 0, _("Illegal character in Volume name \"%s\"\n"),
82 if (db_create_media_record(jcr, jcr->db, mr) &&
83 db_update_pool_record(jcr, jcr->db, &pr)) {
85 Jmsg(jcr, M_INFO, 0, _("Created new Volume \"%s\" in catalog.\n"), mr->VolumeName);
86 Dmsg1(90, "Created new Volume=%s\n", mr->VolumeName);
89 Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
98 static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr)
100 char name[MAXSTRING];
103 /* See if volume already exists */
104 mr->VolumeName[0] = 0;
105 bstrncpy(name, pr->LabelFormat, sizeof(name));
106 for (int i=pr->NumVols+1; i<(int)pr->NumVols+11; i++) {
108 memset(&tmr, 0, sizeof(tmr));
109 sprintf(num, "%04d", i);
110 bstrncpy(tmr.VolumeName, name, sizeof(tmr.VolumeName));
111 bstrncat(tmr.VolumeName, num, sizeof(tmr.VolumeName));
112 if (db_get_media_record(jcr, jcr->db, &tmr)) {
113 Jmsg(jcr, M_WARNING, 0,
114 _("Wanted to create Volume \"%s\", but it already exists. Trying again.\n"),
118 bstrncpy(mr->VolumeName, name, sizeof(mr->VolumeName));
119 bstrncat(mr->VolumeName, num, sizeof(mr->VolumeName));
120 break; /* Got good name */
122 if (mr->VolumeName[0] == 0) {
123 Jmsg(jcr, M_ERROR, 0, _("Too many failures. Giving up creating Volume name.\n"));
129 static int date_item(JCR *jcr, int code,
130 const char **val_ptr, int *val_len, int *val_size)
133 time_t now = time(NULL);
134 localtime_r(&now, &tm);
140 val = tm.tm_year + 1900;
157 case 7: /* Week day */
161 bsnprintf(buf, sizeof(buf), "%d", val);
162 *val_ptr = bstrdup(buf);
163 *val_len = strlen(buf);
164 *val_size = *val_len;
168 static int job_item(JCR *jcr, int code,
169 const char **val_ptr, int *val_len, int *val_size)
178 case 2: /* Director's name */
182 str = job_level_to_str(jcr->JobLevel);
185 str = job_type_to_str(jcr->JobType);
188 bsnprintf(buf, sizeof(buf), "%d", jcr->JobId);
192 str = jcr->client_name;
197 case 7: /* NumVols */
198 bsnprintf(buf, sizeof(buf), "%d", jcr->NumVols);
202 str = jcr->client->hdr.name;
205 *val_ptr = bstrdup(str);
206 *val_len = strlen(str);
207 *val_size = *val_len;
212 struct s_built_in_vars {char *var_name; int code; int (*func)(JCR *jcr, int code,
213 const char **val_ptr, int *val_len, int *val_size);};
215 static struct s_built_in_vars built_in_vars[] = {
216 { N_("Year"), 1, date_item},
217 { N_("Month"), 2, date_item},
218 { N_("Day"), 3, date_item},
219 { N_("Hour"), 4, date_item},
220 { N_("Minute"), 5, date_item},
221 { N_("Second"), 6, date_item},
222 { N_("WeekDay"), 7, date_item},
224 { N_("Job"), 1, job_item},
225 { N_("Dir"), 2, job_item},
226 { N_("Level"), 3, job_item},
227 { N_("Type"), 4, job_item},
228 { N_("JobId"), 5, job_item},
229 { N_("Client"), 6, job_item},
230 { N_("NumVols"), 7, job_item},
231 { N_("Pool"), 8, job_item},
237 static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx,
238 const char *var_ptr, int var_len, int var_index,
239 const char **val_ptr, int *val_len, int *val_size)
241 JCR *jcr = (JCR *)my_ctx;
244 for (int i=0; _(built_in_vars[i].var_name); i++) {
245 if (strncmp(_(built_in_vars[i].var_name), var_ptr, var_len) == 0) {
246 stat = (*built_in_vars[i].func)(jcr, built_in_vars[i].code,
247 val_ptr, val_len, val_size);
254 return VAR_ERR_UNDEFINED_VARIABLE;
259 * Search counter variables
261 static var_rc_t lookup_counter_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)
266 var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE;
268 if (var_len > (int)sizeof(buf) - 1) {
269 return VAR_ERR_OUT_OF_MEMORY;
271 memcpy(buf, var_ptr, var_len);
274 for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
275 if (strcmp(counter->hdr.name, buf) == 0) {
276 bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue);
277 *val_ptr = bstrdup(buf);
278 *val_len = strlen(buf);
279 *val_size = *val_len;
282 JCR *jcr = (JCR *)my_ctx;
283 memset(&cr, 0, sizeof(cr));
284 bstrncpy(cr.Counter, counter->hdr.name, sizeof(cr.Counter));
285 cr.MinValue = counter->MinValue;
286 cr.MaxValue = counter->MaxValue;
287 cr.CurrentValue = ++counter->CurrentValue;
288 bstrncpy(cr.WrapCounter, counter->WrapCounter->hdr.name, sizeof(cr.WrapCounter));
289 if (!db_update_counter_record(jcr, jcr->db, &cr)) {
290 Jmsg(jcr, M_ERROR, 0, _("Count not update counter %s: ERR=%s\n"),
291 counter->hdr.name, db_strerror(jcr->db));
304 * Called here to look up a variable
306 static var_rc_t lookup_var(var_t *ctx, void *my_ctx,
307 const char *var_ptr, int var_len, int var_inc, int var_index,
308 const char **val_ptr, int *val_len, int *val_size)
310 char buf[MAXSTRING], *val, *p, *v;
314 if ((stat = lookup_built_in_var(ctx, my_ctx, var_ptr, var_len, var_index,
315 val_ptr, val_len, val_size)) == VAR_OK) {
319 if ((stat = lookup_counter_var(ctx, my_ctx, var_ptr, var_len, var_inc, var_index,
320 val_ptr, val_len, val_size)) == VAR_OK) {
324 /* Look in environment */
325 if (var_len > (int)sizeof(buf) - 1) {
326 return VAR_ERR_OUT_OF_MEMORY;
328 memcpy(buf, var_ptr, var_len + 1);
330 // Dmsg1(000, "Var=%s\n", buf);
332 if ((val = getenv(buf)) == NULL) {
333 return VAR_ERR_UNDEFINED_VARIABLE;
335 if (var_index == 0) {
337 *val_len = strlen(val);
341 /* He wants to index the "array" */
343 /* Find the size of the "array"
344 * each element is separated by a |
346 for (p = val; *p; p++) {
352 // Dmsg3(000, "For %s, reqest index=%d have=%d\n",
353 // buf, var_index, count);
354 if (var_index < 0 || var_index > count) {
355 return VAR_ERR_SUBMATCH_OUT_OF_RANGE;
357 /* Now find the particular item (var_index) he wants */
361 if (count < var_index) {
370 if (p-val > (int)sizeof(buf) - 1) {
371 return VAR_ERR_OUT_OF_MEMORY;
373 // Dmsg2(000, "val=%s len=%d\n", val, p-val);
374 /* Make a copy of item, and pass it back */
375 v = (char *)malloc(p-val+1);
376 memcpy(v, val, p-val);
381 // Dmsg1(000, "v=%s\n", v);
386 * Called here to do a special operation on a variable
387 * op_ptr points to the special operation code (not EOS terminated)
388 * arg_ptr points to argument to special op code
389 * val_ptr points to the value string
390 * out_ptr points to string to be returned
392 static var_rc_t operate_var(var_t *var, void *my_ctx,
393 const char *op_ptr, int op_len,
394 const char *arg_ptr, int arg_len,
395 const char *val_ptr, int val_len,
396 char **out_ptr, int *out_len, int *out_size)
398 var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION;
399 Dmsg0(000, "Enter operate_var\n");
404 if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) {
406 if (val_len > (int)sizeof(buf) - 1) {
407 return VAR_ERR_OUT_OF_MEMORY;
409 memcpy(buf, arg_ptr, arg_len);
411 Dmsg1(000, "Arg=%s\n", buf);
412 memcpy(buf, val_ptr, val_len);
414 Dmsg1(000, "Val=%s\n", buf);
416 for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) {
417 if (strcmp(counter->hdr.name, buf) == 0) {
418 Dmsg2(000, "counter=%s val=%s\n", counter->hdr.name, buf);
430 * Perform full substitution on Label
432 static int perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr)
440 inp = pr->LabelFormat;
441 in_len = strlen(inp);
446 jcr->NumVols = pr->NumVols;
448 if ((stat = var_create(&var_ctx)) != VAR_OK) {
449 Jmsg(jcr, M_ERROR, 0, _("Cannot create var context: ERR=%s\n"), var_strerror(var_ctx, stat));
452 /* define callback */
453 if ((stat = var_config(var_ctx, VAR_CONFIG_CB_VALUE, lookup_var, (void *)jcr)) != VAR_OK) {
454 Jmsg(jcr, M_ERROR, 0, _("Cannot set var callback: ERR=%s\n"), var_strerror(var_ctx, stat));
459 /* define special operations */
460 if ((stat = var_config(var_ctx, VAR_CONFIG_CB_OPERATION, operate_var, (void *)jcr)) != VAR_OK) {
461 Jmsg(jcr, M_ERROR, 0, _("Cannot set var operate: ERR=%s\n"), var_strerror(var_ctx, stat));
465 /* unescape in place */
466 if ((stat = var_unescape(var_ctx, inp, in_len, inp, in_len+1, 0)) != VAR_OK) {
467 Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
471 in_len = strlen(inp);
473 /* expand variables */
474 if ((stat = var_expand(var_ctx, inp, in_len, &outp, &out_len, 1)) != VAR_OK) {
475 Jmsg(jcr, M_ERROR, 0, _("Cannot expand LabelFormat \"%s\": ERR=%s\n"),
476 inp, var_strerror(var_ctx, stat));
480 /* unescape once more in place */
481 if ((stat = var_unescape(var_ctx, outp, out_len, outp, out_len+1, 1)) != VAR_OK) {
482 Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat));
486 bstrncpy(mr->VolumeName, outp, sizeof(mr->VolumeName));
491 /* destroy expansion context */
492 if ((stat = var_destroy(var_ctx)) != VAR_OK) {
493 Jmsg(jcr, M_ERROR, 0, _("Cannot destroy var context: ERR=%s\n"), var_strerror(var_ctx, stat));