]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/newvol.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / dird / newvol.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5
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.
8
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.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Bacula Director -- newvol.c -- creates new Volumes in
22  *    catalog Media table from the LabelFormat specification.
23  *
24  *     Kern Sibbald, May MMI
25  *
26  *    This routine runs as a thread and must be thread reentrant.
27  *
28  *  Basic tasks done here:
29  *      If possible create a new Media entry
30  *
31  */
32
33 #include "bacula.h"
34 #include "dird.h"
35
36 /* Forward referenced functions */
37 static bool create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr);
38 static bool perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr);
39
40
41 /*
42  * Automatic Volume name creation using the LabelFormat
43  *
44  *  The media record must have the PoolId filled in when
45  *   calling this routine.
46  */
47 bool newVolume(JCR *jcr, MEDIA_DBR *mr, STORE *store)
48 {
49    POOL_DBR pr;
50
51    memset(&pr, 0, sizeof(pr));
52
53    /* See if we can create a new Volume */
54    db_lock(jcr->db);
55    pr.PoolId = mr->PoolId;
56    if (!db_get_pool_numvols(jcr, jcr->db, &pr)) {
57       goto bail_out;
58    }
59    if (pr.MaxVols == 0 || pr.NumVols < pr.MaxVols) {
60       mr->clear();
61       set_pool_dbr_defaults_in_media_dbr(mr, &pr);
62       jcr->VolumeName[0] = 0;
63       bstrncpy(mr->MediaType, jcr->wstore->media_type, sizeof(mr->MediaType));
64       generate_plugin_event(jcr, bDirEventNewVolume); /* return void... */
65       if (jcr->VolumeName[0] && is_volume_name_legal(NULL, jcr->VolumeName)) {
66          bstrncpy(mr->VolumeName, jcr->VolumeName, sizeof(mr->VolumeName));
67       /* Check for special characters */
68       } else if (pr.LabelFormat[0] && pr.LabelFormat[0] != '*') {
69          if (is_volume_name_legal(NULL, pr.LabelFormat)) {
70             /* No special characters, so apply simple algorithm */
71             if (!create_simple_name(jcr, mr, &pr)) {
72                goto bail_out;
73             }
74          } else {  /* try full substitution */
75             /* Found special characters, so try substitution */
76             if (!perform_full_name_substitution(jcr, mr, &pr)) {
77                goto bail_out;
78             }
79             if (!is_volume_name_legal(NULL, mr->VolumeName)) {
80                Jmsg(jcr, M_ERROR, 0, _("Illegal character in Volume name \"%s\"\n"),
81                   mr->VolumeName);
82                goto bail_out;
83             }
84          }
85       } else {
86          goto bail_out;
87       }
88       pr.NumVols++;
89       mr->Enabled = 1;
90       set_storageid_in_mr(store, mr);
91       if (db_create_media_record(jcr, jcr->db, mr) &&
92          db_update_pool_record(jcr, jcr->db, &pr)) {
93          Jmsg(jcr, M_INFO, 0, _("Created new Volume=\"%s\", Pool=\"%s\", MediaType=\"%s\" in catalog.\n"),
94             mr->VolumeName, pr.Name, mr->MediaType);
95          Dmsg1(90, "Created new Volume=%s\n", mr->VolumeName);
96          db_unlock(jcr->db);
97          return true;
98       } else {
99          Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
100       }
101    }
102 bail_out:
103    db_unlock(jcr->db);
104    return false;
105 }
106
107 static bool create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr)
108 {
109    char name[MAXSTRING];
110    char num[20];
111    db_int64_ctx ctx;
112    POOL_MEM query(PM_MESSAGE);
113    char ed1[50];
114
115    /* See if volume already exists */
116    mr->VolumeName[0] = 0;
117    bstrncpy(name, pr->LabelFormat, sizeof(name));
118    ctx.value = 0;
119    /* TODO: Remove Pool as it is not used in the query */
120    Mmsg(query, "SELECT MAX(MediaId) FROM Media,Pool WHERE Pool.PoolId=%s",
121         edit_int64(pr->PoolId, ed1));
122    if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) {
123       Jmsg(jcr, M_WARNING, 0, _("SQL failed, but ignored. ERR=%s\n"), db_strerror(jcr->db));
124       ctx.value = pr->NumVols+1;
125    }
126    for (int i=(int)ctx.value+1; i<(int)ctx.value+100; i++) {
127       MEDIA_DBR tmr;
128       sprintf(num, "%04d", i);
129       bstrncpy(tmr.VolumeName, name, sizeof(tmr.VolumeName));
130       bstrncat(tmr.VolumeName, num, sizeof(tmr.VolumeName));
131       if (db_get_media_record(jcr, jcr->db, &tmr)) {
132          Jmsg(jcr, M_WARNING, 0,
133              _("Wanted to create Volume \"%s\", but it already exists. Trying again.\n"),
134              tmr.VolumeName);
135          continue;
136       }
137       bstrncpy(mr->VolumeName, name, sizeof(mr->VolumeName));
138       bstrncat(mr->VolumeName, num, sizeof(mr->VolumeName));
139       break;                    /* Got good name */
140    }
141    if (mr->VolumeName[0] == 0) {
142       Jmsg(jcr, M_ERROR, 0, _("Too many failures. Giving up creating Volume name.\n"));
143       return false;
144    }
145    return true;
146 }
147
148 /*
149  * Perform full substitution on Label
150  */
151 static bool perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr)
152 {
153    bool ok = false;
154    POOLMEM *label = get_pool_memory(PM_FNAME);
155    jcr->NumVols = pr->NumVols;
156    if (variable_expansion(jcr, pr->LabelFormat, &label)) {
157       bstrncpy(mr->VolumeName, label, sizeof(mr->VolumeName));
158       ok = true;
159    }
160    free_pool_memory(label);
161    return ok;
162 }