]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/butil.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / stored / butil.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 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  *  Utility routines for "tool" programs such as bscan, bls,
22  *    bextract, ...  Some routines also used by Bacula.
23  *
24  *    Kern Sibbald, MM
25  *
26  *  Normally nothing in this file is called by the Storage
27  *    daemon because we interact more directly with the user
28  *    i.e. printf, ...
29  */
30
31 #include "bacula.h"
32 #include "stored.h"
33
34 /* Forward referenced functions */
35 static DCR *setup_to_access_device(JCR *jcr, char *dev_name,
36    const char *VolumeName, bool writing, bool read_dedup_data);
37 static DEVRES *find_device_res(char *device_name, bool writing);
38 static void my_free_jcr(JCR *jcr);
39
40 /* Imported variables -- eliminate some day */
41 extern char *configfile;
42
43 #ifdef DEBUG
44 char *rec_state_bits_to_str(DEV_RECORD *rec)
45 {
46    static char buf[200];
47    buf[0] = 0;
48    if (rec->state_bits & REC_NO_HEADER) {
49       strcat(buf, _("Nohdr,"));
50    }
51    if (is_partial_record(rec)) {
52       strcat(buf, _("partial,"));
53    }
54    if (rec->state_bits & REC_BLOCK_EMPTY) {
55       strcat(buf, _("empty,"));
56    }
57    if (rec->state_bits & REC_NO_MATCH) {
58       strcat(buf, _("Nomatch,"));
59    }
60    if (rec->state_bits & REC_CONTINUATION) {
61       strcat(buf, _("cont,"));
62    }
63    if (buf[0]) {
64       buf[strlen(buf)-1] = 0;
65    }
66    return buf;
67 }
68 #endif
69
70 /*
71  * Setup a pointer to my resource me
72  */
73 void setup_me()
74 {
75    LockRes();
76    me = (STORES *)GetNextRes(R_STORAGE, NULL);
77    if (!me) {
78       UnlockRes();
79       Emsg1(M_ERROR_TERM, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
80          configfile);
81    }
82    UnlockRes();
83 }
84
85 /*
86  * Setup a "daemon" JCR for the various standalone
87  *  tools (e.g. bls, bextract, bscan, ...)
88  */
89 JCR *setup_jcr(const char *name, char *dev_name, BSR *bsr,
90                const char *VolumeName, bool writing, bool read_dedup_data)
91 {
92    DCR *dcr;
93    JCR *jcr = new_jcr(sizeof(JCR), my_free_jcr);
94    jcr->bsr = bsr;
95    jcr->VolSessionId = 1;
96    jcr->VolSessionTime = (uint32_t)time(NULL);
97    jcr->NumReadVolumes = 0;
98    jcr->NumWriteVolumes = 0;
99    jcr->JobId = 0;
100    jcr->setJobType(JT_CONSOLE);
101    jcr->setJobLevel(L_FULL);
102    jcr->JobStatus = JS_Terminated;
103    jcr->where = bstrdup("");
104    jcr->job_name = get_pool_memory(PM_FNAME);
105    pm_strcpy(jcr->job_name, "Dummy.Job.Name");
106    jcr->client_name = get_pool_memory(PM_FNAME);
107    pm_strcpy(jcr->client_name, "Dummy.Client.Name");
108    bstrncpy(jcr->Job, name, sizeof(jcr->Job));
109    jcr->fileset_name = get_pool_memory(PM_FNAME);
110    pm_strcpy(jcr->fileset_name, "Dummy.fileset.name");
111    jcr->fileset_md5 = get_pool_memory(PM_FNAME);
112    pm_strcpy(jcr->fileset_md5, "Dummy.fileset.md5");
113    init_autochangers();
114    create_volume_lists();
115
116    dcr = setup_to_access_device(jcr, dev_name, VolumeName, writing, read_dedup_data);
117    if (!dcr) {
118       return NULL;
119    }
120    if (!bsr && VolumeName) {
121       bstrncpy(dcr->VolumeName, VolumeName, sizeof(dcr->VolumeName));
122    }
123    bstrncpy(dcr->pool_name, "Default", sizeof(dcr->pool_name));
124    bstrncpy(dcr->pool_type, "Backup", sizeof(dcr->pool_type));
125    return jcr;
126 }
127
128 /*
129  * Setup device, jcr, and prepare to access device.
130  *   If the caller wants read access, acquire the device, otherwise,
131  *     the caller will do it.
132  */
133 static DCR *setup_to_access_device(JCR *jcr, char *dev_name,
134               const char *VolumeName, bool writing, bool read_dedup_data)
135 {
136    DEVICE *dev;
137    char *p;
138    DEVRES *device;
139    DCR *dcr;
140    char VolName[MAX_NAME_LENGTH];
141
142    init_reservations_lock();
143
144    /*
145     * If no volume name already given and no bsr, and it is a file,
146     * try getting name from Filename
147     */
148    if (VolumeName) {
149       bstrncpy(VolName, VolumeName, sizeof(VolName));
150       if (strlen(VolumeName) >= MAX_NAME_LENGTH) {
151          Jmsg0(jcr, M_ERROR, 0, _("Volume name or names is too long. Please use a .bsr file.\n"));
152       }
153    } else {
154       VolName[0] = 0;
155    }
156    if (!jcr->bsr && VolName[0] == 0) {
157       if (strncmp(dev_name, "/dev/", 5) != 0) {
158          /* Try stripping file part */
159          p = dev_name + strlen(dev_name);
160
161          while (p >= dev_name && !IsPathSeparator(*p))
162             p--;
163          if (IsPathSeparator(*p)) {
164             bstrncpy(VolName, p+1, sizeof(VolName));
165             *p = 0;
166          }
167       }
168    }
169
170    if ((device=find_device_res(dev_name, writing)) == NULL) {
171       Jmsg2(jcr, M_FATAL, 0, _("Cannot find device \"%s\" in config file %s.\n"),
172            dev_name, configfile);
173       return NULL;
174    }
175
176    dev = init_dev(jcr, device);
177    if (!dev) {
178       Jmsg1(jcr, M_FATAL, 0, _("Cannot init device %s\n"), dev_name);
179       return NULL;
180    }
181    device->dev = dev;
182    jcr->dcr = dcr = new_dcr(jcr, NULL, dev, writing);
183    if (VolName[0]) {
184       bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
185    }
186    bstrncpy(dcr->dev_name, device->device_name, sizeof(dcr->dev_name));
187
188    create_restore_volume_list(jcr, true);
189
190    if (!writing) {                      /* read only access? */
191       Dmsg0(100, "Acquire device for read\n");
192       if (!acquire_device_for_read(dcr)) {
193          return NULL;
194       }
195       jcr->read_dcr = dcr;
196    } else {
197       if (!first_open_device(dcr)) {
198          Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), dev->print_name());
199          return NULL;
200       }
201       jcr->dcr = dcr;        /* write dcr */
202    }
203    return dcr;
204 }
205
206
207 /*
208  * Called here when freeing JCR so that we can get rid
209  *  of "daemon" specific memory allocated.
210  */
211 static void my_free_jcr(JCR *jcr)
212 {
213    if (jcr->job_name) {
214       free_pool_memory(jcr->job_name);
215       jcr->job_name = NULL;
216    }
217    if (jcr->client_name) {
218       free_pool_memory(jcr->client_name);
219       jcr->client_name = NULL;
220    }
221    if (jcr->fileset_name) {
222       free_pool_memory(jcr->fileset_name);
223       jcr->fileset_name = NULL;
224    }
225    if (jcr->fileset_md5) {
226       free_pool_memory(jcr->fileset_md5);
227       jcr->fileset_md5 = NULL;
228    }
229    if (jcr->comment) {
230       free_pool_memory(jcr->comment);
231       jcr->comment = NULL;
232    }
233    if (jcr->VolList) {
234       free_restore_volume_list(jcr);
235    }
236    if (jcr->dcr) {
237       free_dcr(jcr->dcr);
238       jcr->dcr = NULL;
239    }
240    return;
241 }
242
243
244 /*
245  * Search for device resource that corresponds to
246  * device name on command line (or default).
247  *
248  * Returns: NULL on failure
249  *          Device resource pointer on success
250  */
251 static DEVRES *find_device_res(char *device_name, bool write_access)
252 {
253    bool found = false;
254    DEVRES *device;
255
256    Dmsg0(900, "Enter find_device_res\n");
257    LockRes();
258    foreach_res(device, R_DEVICE) {
259       Dmsg2(900, "Compare %s and %s\n", device->device_name, device_name);
260       if (strcmp(device->device_name, device_name) == 0) {
261          found = true;
262          break;
263       }
264    }
265    if (!found) {
266       /* Search for name of Device resource rather than archive name */
267       if (device_name[0] == '"') {
268          int len = strlen(device_name);
269          bstrncpy(device_name, device_name+1, len+1);
270          len--;
271          if (len > 0) {
272             device_name[len-1] = 0;   /* zap trailing " */
273          }
274       }
275       foreach_res(device, R_DEVICE) {
276          Dmsg2(900, "Compare %s and %s\n", device->hdr.name, device_name);
277          if (strcmp(device->hdr.name, device_name) == 0) {
278             found = true;
279             break;
280          }
281       }
282    }
283    UnlockRes();
284    if (!found) {
285       Pmsg2(0, _("Could not find device \"%s\" in config file %s.\n"), device_name,
286             configfile);
287       return NULL;
288    }
289    if (write_access) {
290       Pmsg1(0, _("Using device: \"%s\" for writing.\n"), device_name);
291    } else {
292       Pmsg1(0, _("Using device: \"%s\" for reading.\n"), device_name);
293    }
294    return device;
295 }
296
297
298 /*
299  * Device got an error, attempt to analyse it
300  */
301 void display_tape_error_status(JCR *jcr, DEVICE *dev)
302 {
303    uint32_t status;
304
305    status = status_dev(dev);
306    Dmsg1(20, "Device status: %x\n", status);
307    if (status & BMT_EOD)
308       Jmsg(jcr, M_ERROR, 0, _("Unexpected End of Data\n"));
309    else if (status & BMT_EOT)
310       Jmsg(jcr, M_ERROR, 0, _("Unexpected End of Tape\n"));
311    else if (status & BMT_EOF)
312       Jmsg(jcr, M_ERROR, 0, _("Unexpected End of File\n"));
313    else if (status & BMT_DR_OPEN)
314       Jmsg(jcr, M_ERROR, 0, _("Tape Door is Open\n"));
315    else if (!(status & BMT_ONLINE))
316       Jmsg(jcr, M_ERROR, 0, _("Unexpected Tape is Off-line\n"));
317 }