3 * Program to copy a Bacula from one volume to another.
5 * Kern E. Sibbald, October 2002
11 Copyright (C) 2002-2006 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 version 2 as amended with additional clauses defined in the
16 file LICENSE in the main source directory.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 the file LICENSE for additional details.
29 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
31 /* Forward referenced functions */
32 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
35 /* Global variables */
36 static DEVICE *in_dev = NULL;
37 static DEVICE *out_dev = NULL;
38 static JCR *in_jcr; /* input jcr */
39 static JCR *out_jcr; /* output jcr */
40 static BSR *bsr = NULL;
41 static const char *wd = "/tmp";
42 static int list_records = 0;
43 static uint32_t records = 0;
44 static uint32_t jobs = 0;
45 static DEV_BLOCK *out_block;
47 #define CONFIG_FILE "bacula-sd.conf"
48 char *configfile = NULL;
49 STORES *me = NULL; /* our Global resource */
50 bool forge_on = false; /* proceed inspite of I/O errors */
51 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
52 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
58 "Copyright (C) 2002-%s Kern Sibbald.\n"
59 "\nVersion: %s (%s)\n\n"
60 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
61 " -b bootstrap specify a bootstrap file\n"
62 " -c <file> specify configuration file\n"
63 " -d <nn> set debug level to nn\n"
64 " -i specify input Volume names (separated by |)\n"
65 " -o specify output Volume names (separated by |)\n"
66 " -p proceed inspite of errors\n"
68 " -w <dir> specify working directory (default /tmp)\n"
69 " -? print this message\n\n"), BYEAR, VERSION, BDATE);
73 int main (int argc, char *argv[])
76 char *iVolumeName = NULL;
77 char *oVolumeName = NULL;
78 bool ignore_label_errors = false;
80 setlocale(LC_ALL, "");
81 bindtextdomain("bacula", LOCALEDIR);
84 my_name_is(argc, argv, "bcopy");
87 while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
90 bsr = parse_bsr(NULL, optarg);
93 case 'c': /* specify config file */
94 if (configfile != NULL) {
97 configfile = bstrdup(optarg);
100 case 'd': /* debug level */
101 debug_level = atoi(optarg);
102 if (debug_level <= 0)
106 case 'i': /* input Volume name */
107 iVolumeName = optarg;
110 case 'o': /* output Volume name */
111 oVolumeName = optarg;
115 ignore_label_errors = true;
137 Pmsg0(0, _("Wrong number of arguments: \n"));
143 working_directory = wd;
145 if (configfile == NULL) {
146 configfile = bstrdup(CONFIG_FILE);
149 parse_config(configfile);
151 /* Setup and acquire input device for reading */
152 Dmsg0(100, "About to setup input jcr\n");
153 in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
157 in_jcr->ignore_label_errors = ignore_label_errors;
158 in_dev = in_jcr->dcr->dev;
163 /* Setup output device for writing */
164 Dmsg0(100, "About to setup output jcr\n");
165 out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
169 out_dev = out_jcr->dcr->dev;
173 Dmsg0(100, "About to acquire device for writing\n");
174 /* For we must now acquire the device for writing */
175 lock_device(out_dev);
176 if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
177 Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
178 unlock_device(out_dev);
181 unlock_device(out_dev);
182 if (!acquire_device_for_append(out_jcr->dcr)) {
186 out_block = out_jcr->dcr->block;
188 read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
189 if (!write_block_to_device(out_jcr->dcr)) {
190 Pmsg0(000, _("Write of last block failed.\n"));
193 Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
205 * read_records() calls back here for each record it gets
207 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
210 Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
211 rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
212 rec->Stream, rec->data_len);
215 * Check for Start or End of Session Record
218 if (rec->FileIndex < 0) {
221 dump_label_record(in_dcr->dev, rec, 1);
223 switch (rec->FileIndex) {
225 Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
228 Pmsg0(000, _("Volume label not copied.\n"));
234 while (!write_record_to_block(out_block, rec)) {
235 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
237 if (!write_block_to_device(out_jcr->dcr)) {
238 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
239 out_dev->print_name(), out_dev->bstrerror());
240 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
241 out_dev->bstrerror());
244 if (!write_block_to_device(out_jcr->dcr)) {
245 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
246 out_dev->print_name(), out_dev->bstrerror());
247 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
248 out_dev->bstrerror());
252 Pmsg0(000, _("EOM label not copied.\n"));
254 case EOT_LABEL: /* end of all tapes */
255 Pmsg0(000, _("EOT label not copied.\n"));
264 while (!write_record_to_block(out_block, rec)) {
265 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
267 if (!write_block_to_device(out_jcr->dcr)) {
268 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
269 out_dev->print_name(), out_dev->bstrerror());
270 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
271 out_dev->bstrerror());
279 /* Dummies to replace askdir.c */
280 bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
281 bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
282 bool dir_create_jobmedia_record(DCR *dcr) { return 1; }
283 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
284 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
285 bool dir_send_job_status(JCR *jcr) {return 1;}
288 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
290 DEVICE *dev = dcr->dev;
291 fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
292 dcr->VolumeName, dev->print_name());
298 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
300 Dmsg0(100, "Fake dir_get_volume_info\n");
301 bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
302 dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
303 Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);