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