]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
kes Apply patch from bug #1049 to prevent stripping the path on a
[bacula/bacula] / bacula / src / stored / bcopy.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *  Program to copy a Bacula from one volume to another.
31  *
32  *   Kern E. Sibbald, October 2002
33  *
34  *
35  *   Version $Id$
36  */
37
38 #include "bacula.h"
39 #include "stored.h"
40
41 /* Dummy functions */
42 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
43
44 /* Forward referenced functions */
45 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
46 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
47
48
49 /* Global variables */
50 static DEVICE *in_dev = NULL;
51 static DEVICE *out_dev = NULL;
52 static JCR *in_jcr;                    /* input jcr */
53 static JCR *out_jcr;                   /* output jcr */
54 static BSR *bsr = NULL;
55 static const char *wd = "/tmp";
56 static bool list_records = false;
57 static uint32_t records = 0;
58 static uint32_t jobs = 0;
59 static DEV_BLOCK *out_block;
60 static SESSION_LABEL sessrec;
61
62 #define CONFIG_FILE "bacula-sd.conf"
63 char *configfile = NULL;
64 STORES *me = NULL;                    /* our Global resource */
65 bool forge_on = false;                /* proceed inspite of I/O errors */
66 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
67 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
68
69
70 static void usage()
71 {
72    fprintf(stderr, _(
73 PROG_COPYRIGHT
74 "\nVersion: %s (%s)\n\n"
75 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
76 "       -b bootstrap      specify a bootstrap file\n"
77 "       -c <file>         specify configuration file\n"
78 "       -d <nn>           set debug level to <nn>\n"
79 "       -dt               print timestamp in debug output\n"
80 "       -i                specify input Volume names (separated by |)\n"
81 "       -o                specify output Volume names (separated by |)\n"
82 "       -p                proceed inspite of errors\n"
83 "       -v                verbose\n"
84 "       -w <dir>          specify working directory (default /tmp)\n"
85 "       -?                print this message\n\n"), 2002, VERSION, BDATE);
86    exit(1);
87 }
88
89 int main (int argc, char *argv[])
90 {
91    int ch;
92    char *iVolumeName = NULL;
93    char *oVolumeName = NULL;
94    bool ignore_label_errors = false;
95    bool ok;
96
97    setlocale(LC_ALL, "");
98    bindtextdomain("bacula", LOCALEDIR);
99    textdomain("bacula");
100    init_stack_dump();
101
102    my_name_is(argc, argv, "bcopy");
103    init_msg(NULL, NULL);
104
105    while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
106       switch (ch) {
107       case 'b':
108          bsr = parse_bsr(NULL, optarg);
109          break;
110
111       case 'c':                    /* specify config file */
112          if (configfile != NULL) {
113             free(configfile);
114          }
115          configfile = bstrdup(optarg);
116          break;
117
118       case 'd':                    /* debug level */
119          if (*optarg == 't') {
120             dbg_timestamp = true;
121          } else {
122             debug_level = atoi(optarg);
123             if (debug_level <= 0) {
124                debug_level = 1;
125             }
126          }
127          break;
128
129       case 'i':                    /* input Volume name */
130          iVolumeName = optarg;
131          break;
132
133       case 'o':                    /* output Volume name */
134          oVolumeName = optarg;
135          break;
136
137       case 'p':
138          ignore_label_errors = true;
139          forge_on = true;
140          break;
141
142       case 'v':
143          verbose++;
144          break;
145
146       case 'w':
147          wd = optarg;
148          break;
149
150       case '?':
151       default:
152          usage();
153
154       }
155    }
156    argc -= optind;
157    argv += optind;
158
159    if (argc != 2) {
160       Pmsg0(0, _("Wrong number of arguments: \n"));
161       usage();
162    }
163
164    OSDependentInit();
165
166    working_directory = wd;
167
168    if (configfile == NULL) {
169       configfile = bstrdup(CONFIG_FILE);
170    }
171
172    parse_config(configfile);
173
174    /* Setup and acquire input device for reading */
175    Dmsg0(100, "About to setup input jcr\n");
176    in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
177    if (!in_jcr) {
178       exit(1);
179    }
180    in_jcr->ignore_label_errors = ignore_label_errors;
181    in_dev = in_jcr->dcr->dev;
182    if (!in_dev) {
183       exit(1);
184    }
185
186    /* Setup output device for writing */
187    Dmsg0(100, "About to setup output jcr\n");
188    out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
189    if (!out_jcr) {
190       exit(1);
191    }
192    out_dev = out_jcr->dcr->dev;
193    if (!out_dev) {
194       exit(1);
195    }
196    Dmsg0(100, "About to acquire device for writing\n");
197    /* For we must now acquire the device for writing */
198    out_dev->r_dlock();
199    if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
200       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
201       out_dev->dunlock();
202       exit(1);
203    }
204    out_dev->dunlock();
205    if (!acquire_device_for_append(out_jcr->dcr)) {
206       free_jcr(in_jcr);
207       exit(1);
208    }
209    out_block = out_jcr->dcr->block;
210
211    ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
212
213    if (ok || out_dev->can_write()) {
214       if (!write_block_to_device(out_jcr->dcr)) {
215          Pmsg0(000, _("Write of last block failed.\n"));
216       }
217    }
218
219    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
220
221    free_jcr(in_jcr);
222    free_jcr(out_jcr);
223
224    in_dev->term();
225    out_dev->term();
226    return 0;
227 }
228
229
230 /*
231  * read_records() calls back here for each record it gets
232  */
233 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
234 {
235    if (list_records) {
236       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
237             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
238             rec->Stream, rec->data_len);
239    }
240    /*
241     * Check for Start or End of Session Record
242     *
243     */
244    if (rec->FileIndex < 0) {
245       get_session_record(in_dcr->dev, rec, &sessrec);
246
247       if (verbose > 1) {
248          dump_label_record(in_dcr->dev, rec, 1);
249       }
250       switch (rec->FileIndex) {
251       case PRE_LABEL:
252          Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
253          return false;
254       case VOL_LABEL:
255          Pmsg0(000, _("Volume label not copied.\n"));
256          return true;
257       case SOS_LABEL:
258          jobs++;
259          break;
260       case EOS_LABEL:
261          while (!write_record_to_block(out_block, rec)) {
262             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
263                        rec->remainder);
264             if (!write_block_to_device(out_jcr->dcr)) {
265                Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
266                   out_dev->print_name(), out_dev->bstrerror());
267                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
268                      out_dev->bstrerror());
269                return false;
270             }
271          }
272          if (!write_block_to_device(out_jcr->dcr)) {
273             Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
274                out_dev->print_name(), out_dev->bstrerror());
275             Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
276                   out_dev->bstrerror());
277             return false;
278          }
279          return true;
280       case EOM_LABEL:
281          Pmsg0(000, _("EOM label not copied.\n"));
282          return true;
283       case EOT_LABEL:              /* end of all tapes */
284          Pmsg0(000, _("EOT label not copied.\n"));
285          return true;
286       default:
287          return true;
288       }
289    }
290
291    /*  Write record */
292    records++;
293    while (!write_record_to_block(out_block, rec)) {
294       Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
295                  rec->remainder);
296       if (!write_block_to_device(out_jcr->dcr)) {
297          Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
298             out_dev->print_name(), out_dev->bstrerror());
299          Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
300                out_dev->bstrerror());
301          return false;
302       }
303    }
304    return true;
305 }
306
307 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
308 {
309    const char *rtype;
310    memset(sessrec, 0, sizeof(sessrec));
311    switch (rec->FileIndex) {
312    case PRE_LABEL:
313       rtype = _("Fresh Volume Label");
314       break;
315    case VOL_LABEL:
316       rtype = _("Volume Label");
317       unser_volume_label(dev, rec);
318       break;
319    case SOS_LABEL:
320       rtype = _("Begin Job Session");
321       unser_session_label(sessrec, rec);
322       break;
323    case EOS_LABEL:
324       rtype = _("End Job Session");
325       unser_session_label(sessrec, rec);
326       break;
327    case 0:
328    case EOM_LABEL:
329       rtype = _("End of Medium");
330       break;
331    default:
332       rtype = _("Unknown");
333       break;
334    }
335    Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
336          rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
337    if (verbose) {
338       Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
339             rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
340    }
341 }
342
343
344 /* Dummies to replace askdir.c */
345 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
346 bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
347 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
348 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
349 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
350 bool    dir_send_job_status(JCR *jcr) {return 1;}
351
352
353 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
354 {
355    DEVICE *dev = dcr->dev;
356    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
357       dcr->VolumeName, dev->print_name());
358    dev->close();
359    getchar();
360    return true;
361 }
362
363 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing)
364 {
365    Dmsg0(100, "Fake dir_get_volume_info\n");
366    bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
367    dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
368    Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);
369    return 1;
370 }