]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/butil.c
Fix automatic labeling of File volumes, which was broken by new
[bacula/bacula] / bacula / src / stored / butil.c
1 /*
2  *
3  *  Utility routines for "tool" programs such as bscan, bls,
4  *    bextract, ...  Some routines also used by Bacula.
5  *
6  *    Kern Sibbald, MM
7  *
8  *  Normally nothing in this file is called by the Storage
9  *    daemon because we interact more directly with the user
10  *    i.e. printf, ...
11  *
12  *   Version $Id$
13  */
14 /*
15    Bacula® - The Network Backup Solution
16
17    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
18
19    The main author of Bacula is Kern Sibbald, with contributions from
20    many others, a complete list can be found in the file AUTHORS.
21    This program is Free Software; you can redistribute it and/or
22    modify it under the terms of version two of the GNU General Public
23    License as published by the Free Software Foundation plus additions
24    that are listed in the file LICENSE.
25
26    This program is distributed in the hope that it will be useful, but
27    WITHOUT ANY WARRANTY; without even the implied warranty of
28    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29    General Public License for more details.
30
31    You should have received a copy of the GNU General Public License
32    along with this program; if not, write to the Free Software
33    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
34    02110-1301, USA.
35
36    Bacula® is a registered trademark of John Walker.
37    The licensor of Bacula is the Free Software Foundation Europe
38    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
39    Switzerland, email:ftf@fsfeurope.org.
40 */
41
42 #include "bacula.h"
43 #include "stored.h"
44
45 /* Forward referenced functions */
46 static DCR *setup_to_access_device(JCR *jcr, char *dev_name, const char *VolumeName, int mode);
47 static DEVRES *find_device_res(char *device_name, int mode);
48 static void my_free_jcr(JCR *jcr);
49
50 /* Imported variables -- eliminate some day */
51 extern char *configfile;
52
53 #ifdef DEBUG
54 char *rec_state_to_str(DEV_RECORD *rec)
55 {
56    static char buf[200];
57    buf[0] = 0;
58    if (rec->state & REC_NO_HEADER) {
59       strcat(buf, _("Nohdr,"));
60    }
61    if (is_partial_record(rec)) {
62       strcat(buf, _("partial,"));
63    }
64    if (rec->state & REC_BLOCK_EMPTY) {
65       strcat(buf, _("empty,"));
66    }
67    if (rec->state & REC_NO_MATCH) {
68       strcat(buf, _("Nomatch,"));
69    }
70    if (rec->state & REC_CONTINUATION) {
71       strcat(buf, _("cont,"));
72    }
73    if (buf[0]) {
74       buf[strlen(buf)-1] = 0;
75    }
76    return buf;
77 }
78 #endif
79
80 /*
81  * Setup a "daemon" JCR for the various standalone
82  *  tools (e.g. bls, bextract, bscan, ...)
83  */
84 JCR *setup_jcr(const char *name, char *dev_name, BSR *bsr,
85                const char *VolumeName, int mode)
86 {
87    DCR *dcr;
88    JCR *jcr = new_jcr(sizeof(JCR), my_free_jcr);
89    jcr->bsr = bsr;
90    jcr->VolSessionId = 1;
91    jcr->VolSessionTime = (uint32_t)time(NULL);
92    jcr->NumVolumes = 0;
93    jcr->JobId = 0;
94    jcr->JobType = JT_CONSOLE;
95    jcr->JobLevel = L_FULL;
96    jcr->JobStatus = JS_Terminated;
97    jcr->where = bstrdup("");
98    jcr->job_name = get_pool_memory(PM_FNAME);
99    pm_strcpy(jcr->job_name, "Dummy.Job.Name");
100    jcr->client_name = get_pool_memory(PM_FNAME);
101    pm_strcpy(jcr->client_name, "Dummy.Client.Name");
102    bstrncpy(jcr->Job, name, sizeof(jcr->Job));
103    jcr->fileset_name = get_pool_memory(PM_FNAME);
104    pm_strcpy(jcr->fileset_name, "Dummy.fileset.name");
105    jcr->fileset_md5 = get_pool_memory(PM_FNAME);
106    pm_strcpy(jcr->fileset_md5, "Dummy.fileset.md5");
107
108    init_autochangers();
109    create_volume_list();
110
111    dcr = setup_to_access_device(jcr, dev_name, VolumeName, mode);
112    if (!dcr) {
113       return NULL;
114    }
115    if (!bsr && VolumeName) {
116       bstrncpy(dcr->VolumeName, VolumeName, sizeof(dcr->VolumeName));
117    }
118    bstrncpy(dcr->pool_name, "Default", sizeof(dcr->pool_name));
119    bstrncpy(dcr->pool_type, "Backup", sizeof(dcr->pool_type));
120    return jcr;
121 }
122
123 /*
124  * Setup device, jcr, and prepare to access device.
125  *   If the caller wants read access, acquire the device, otherwise,
126  *     the caller will do it.
127  */
128 static DCR *setup_to_access_device(JCR *jcr, char *dev_name, 
129               const char *VolumeName, int mode)
130 {
131    DEVICE *dev;
132    char *p;
133    DEVRES *device;
134    DCR *dcr;
135    char VolName[MAX_NAME_LENGTH];
136
137    init_reservations_lock();
138
139    /*
140     * If no volume name already given and no bsr, and it is a file,
141     * try getting name from Filename
142     */
143    if (VolumeName) {
144       bstrncpy(VolName, VolumeName, sizeof(VolName));
145       if (strlen(VolumeName) >= MAX_NAME_LENGTH) {
146          Jmsg0(jcr, M_ERROR, 0, _("Volume name or names is too long. Please use a .bsr file.\n"));
147       }
148    } else {
149       VolName[0] = 0;
150    }
151    if (!jcr->bsr && VolName[0] == 0) {
152       if (strncmp(dev_name, "/dev/", 5) != 0) {
153          /* Try stripping file part */
154          p = dev_name + strlen(dev_name);
155
156          while (p >= dev_name && !IsPathSeparator(*p))
157             p--;
158          if (IsPathSeparator(*p)) {
159             bstrncpy(VolName, p+1, sizeof(VolName));
160             *p = 0;
161          }
162       }
163    }
164
165    if ((device=find_device_res(dev_name, mode)) == NULL) {
166       Jmsg2(jcr, M_FATAL, 0, _("Cannot find device \"%s\" in config file %s.\n"),
167            dev_name, configfile);
168       return NULL;
169    }
170
171    dev = init_dev(jcr, device);
172    if (!dev) {
173       Jmsg1(jcr, M_FATAL, 0, _("Cannot init device %s\n"), dev_name);
174       return NULL;
175    }
176    device->dev = dev;
177    dcr = new_dcr(jcr, dev);
178    jcr->dcr = dcr;
179    if (VolName[0]) {
180       bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
181    }
182    bstrncpy(dcr->dev_name, device->device_name, sizeof(dcr->dev_name));
183
184    create_restore_volume_list(jcr);
185
186    if (mode) {                        /* read only access? */
187       Dmsg0(100, "Acquire device for read\n");
188       if (!acquire_device_for_read(dcr)) {
189          return NULL;
190       }
191       jcr->read_dcr = dcr;
192    } else {
193       if (!first_open_device(dcr)) {
194          Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), dev->print_name());
195          return NULL;
196       }
197       jcr->dcr = dcr;        /* write dcr */
198    }
199    return dcr;
200 }
201
202
203 /*
204  * Called here when freeing JCR so that we can get rid
205  *  of "daemon" specific memory allocated.
206  */
207 static void my_free_jcr(JCR *jcr)
208 {
209    if (jcr->job_name) {
210       free_pool_memory(jcr->job_name);
211       jcr->job_name = NULL;
212    }
213    if (jcr->client_name) {
214       free_pool_memory(jcr->client_name);
215       jcr->client_name = NULL;
216    }
217    if (jcr->fileset_name) {
218       free_pool_memory(jcr->fileset_name);
219       jcr->fileset_name = NULL;
220    }
221    if (jcr->fileset_md5) {
222       free_pool_memory(jcr->fileset_md5);
223       jcr->fileset_md5 = NULL;
224    }
225    if (jcr->VolList) {
226       free_restore_volume_list(jcr);
227    }
228    if (jcr->dcr) {
229       free_dcr(jcr->dcr);
230       jcr->dcr = NULL;
231    }
232    return;
233 }
234
235
236 /*
237  * Search for device resource that corresponds to
238  * device name on command line (or default).
239  *
240  * Returns: NULL on failure
241  *          Device resource pointer on success
242  */
243 static DEVRES *find_device_res(char *device_name, int read_access)
244 {
245    bool found = false;
246    DEVRES *device;
247
248    Dmsg0(900, "Enter find_device_res\n");
249    LockRes();
250    foreach_res(device, R_DEVICE) {
251       Dmsg2(900, "Compare %s and %s\n", device->device_name, device_name);
252       if (strcmp(device->device_name, device_name) == 0) {
253          found = true;
254          break;
255       }
256    }
257    if (!found) {
258       /* Search for name of Device resource rather than archive name */
259       if (device_name[0] == '"') {
260          int len = strlen(device_name);
261          bstrncpy(device_name, device_name+1, len+1);
262          len--;
263          if (len > 0) {
264             device_name[len-1] = 0;   /* zap trailing " */
265          }
266       }
267       foreach_res(device, R_DEVICE) {
268          Dmsg2(900, "Compare %s and %s\n", device->hdr.name, device_name);
269          if (strcmp(device->hdr.name, device_name) == 0) {
270             found = true;
271             break;
272          }
273       }
274    }
275    UnlockRes();
276    if (!found) {
277       Pmsg2(0, _("Could not find device \"%s\" in config file %s.\n"), device_name,
278             configfile);
279       return NULL;
280    }
281    if (read_access) {
282       Pmsg1(0, _("Using device: \"%s\" for reading.\n"), device_name);
283    }
284    else {
285       Pmsg1(0, _("Using device: \"%s\" for writing.\n"), device_name);
286    }
287    return device;
288 }
289
290
291 /*
292  * Device got an error, attempt to analyse it
293  */
294 void display_tape_error_status(JCR *jcr, DEVICE *dev)
295 {
296    uint32_t status;
297
298    status = status_dev(dev);
299    Dmsg1(20, "Device status: %x\n", status);
300    if (status & BMT_EOD)
301       Jmsg(jcr, M_ERROR, 0, _("Unexpected End of Data\n"));
302    else if (status & BMT_EOT)
303       Jmsg(jcr, M_ERROR, 0, _("Unexpected End of Tape\n"));
304    else if (status & BMT_EOF)
305       Jmsg(jcr, M_ERROR, 0, _("Unexpected End of File\n"));
306    else if (status & BMT_DR_OPEN)
307       Jmsg(jcr, M_ERROR, 0, _("Tape Door is Open\n"));
308    else if (!(status & BMT_ONLINE))
309       Jmsg(jcr, M_ERROR, 0, _("Unexpected Tape is Off-line\n"));
310 }