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);
85 my_name_is(argc, argv, "bcopy");
88 while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
91 bsr = parse_bsr(NULL, optarg);
94 case 'c': /* specify config file */
95 if (configfile != NULL) {
98 configfile = bstrdup(optarg);
101 case 'd': /* debug level */
102 debug_level = atoi(optarg);
103 if (debug_level <= 0)
107 case 'i': /* input Volume name */
108 iVolumeName = optarg;
111 case 'o': /* output Volume name */
112 oVolumeName = optarg;
116 ignore_label_errors = true;
138 Pmsg0(0, _("Wrong number of arguments: \n"));
144 working_directory = wd;
146 if (configfile == NULL) {
147 configfile = bstrdup(CONFIG_FILE);
150 parse_config(configfile);
152 /* Setup and acquire input device for reading */
153 Dmsg0(100, "About to setup input jcr\n");
154 in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
158 in_jcr->ignore_label_errors = ignore_label_errors;
159 in_dev = in_jcr->dcr->dev;
164 /* Setup output device for writing */
165 Dmsg0(100, "About to setup output jcr\n");
166 out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
170 out_dev = out_jcr->dcr->dev;
174 Dmsg0(100, "About to acquire device for writing\n");
175 /* For we must now acquire the device for writing */
176 lock_device(out_dev);
177 if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
178 Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
179 unlock_device(out_dev);
182 unlock_device(out_dev);
183 if (!acquire_device_for_append(out_jcr->dcr)) {
187 out_block = out_jcr->dcr->block;
189 read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
190 if (!write_block_to_device(out_jcr->dcr)) {
191 Pmsg0(000, _("Write of last block failed.\n"));
194 Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
206 * read_records() calls back here for each record it gets
208 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
211 Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
212 rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
213 rec->Stream, rec->data_len);
216 * Check for Start or End of Session Record
219 if (rec->FileIndex < 0) {
222 dump_label_record(in_dcr->dev, rec, 1);
224 switch (rec->FileIndex) {
226 Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
229 Pmsg0(000, _("Volume label not copied.\n"));
235 while (!write_record_to_block(out_block, rec)) {
236 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
238 if (!write_block_to_device(out_jcr->dcr)) {
239 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
240 out_dev->print_name(), out_dev->bstrerror());
241 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
242 out_dev->bstrerror());
245 if (!write_block_to_device(out_jcr->dcr)) {
246 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
247 out_dev->print_name(), out_dev->bstrerror());
248 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
249 out_dev->bstrerror());
253 Pmsg0(000, _("EOM label not copied.\n"));
255 case EOT_LABEL: /* end of all tapes */
256 Pmsg0(000, _("EOT label not copied.\n"));
265 while (!write_record_to_block(out_block, rec)) {
266 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
268 if (!write_block_to_device(out_jcr->dcr)) {
269 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
270 out_dev->print_name(), out_dev->bstrerror());
271 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
272 out_dev->bstrerror());
280 /* Dummies to replace askdir.c */
281 bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
282 bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
283 bool dir_create_jobmedia_record(DCR *dcr) { return 1; }
284 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
285 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
286 bool dir_send_job_status(JCR *jcr) {return 1;}
289 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
291 DEVICE *dev = dcr->dev;
292 fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
293 dcr->VolumeName, dev->print_name());
299 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
301 Dmsg0(100, "Fake dir_get_volume_info\n");
302 bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
303 dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
304 Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);