3 * Program to copy a Bacula from one volume to another.
5 * Kern E. Sibbald, October 2002
11 Copyright (C) 2002-2005 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 ammended 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-2005 Kern Sibbald.\n"
59 "\nVersion: " VERSION " (" BDATE ")\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"));
73 int main (int argc, char *argv[])
76 char *iVolumeName = NULL;
77 char *oVolumeName = NULL;
78 bool ignore_label_errors = false;
80 my_name_is(argc, argv, "bcopy");
83 while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
86 bsr = parse_bsr(NULL, optarg);
89 case 'c': /* specify config file */
90 if (configfile != NULL) {
93 configfile = bstrdup(optarg);
96 case 'd': /* debug level */
97 debug_level = atoi(optarg);
102 case 'i': /* input Volume name */
103 iVolumeName = optarg;
106 case 'o': /* output Volume name */
107 oVolumeName = optarg;
111 ignore_label_errors = true;
133 Pmsg0(0, _("Wrong number of arguments: \n"));
137 working_directory = wd;
139 if (configfile == NULL) {
140 configfile = bstrdup(CONFIG_FILE);
143 parse_config(configfile);
145 /* Setup and acquire input device for reading */
146 in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
150 in_jcr->ignore_label_errors = ignore_label_errors;
151 in_dev = in_jcr->dcr->dev;
156 /* Setup output device for writing */
157 out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
161 out_dev = out_jcr->dcr->dev;
165 /* For we must now acquire the device for writing */
166 lock_device(out_dev);
167 if (open_dev(out_dev, out_jcr->dcr->VolumeName, OPEN_READ_WRITE) < 0) {
168 Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
169 unlock_device(out_dev);
172 unlock_device(out_dev);
173 if (!acquire_device_for_append(out_jcr->dcr)) {
177 out_block = out_jcr->dcr->block;
179 read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
180 if (!write_block_to_device(out_jcr->dcr)) {
181 Pmsg0(000, _("Write of last block failed.\n"));
184 Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
196 * read_records() calls back here for each record it gets
198 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
201 Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
202 rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
203 rec->Stream, rec->data_len);
206 * Check for Start or End of Session Record
209 if (rec->FileIndex < 0) {
212 dump_label_record(in_dcr->dev, rec, 1);
214 switch (rec->FileIndex) {
216 Pmsg0(000, "Volume is prelabeled. This volume cannot be copied.\n");
219 Pmsg0(000, "Volume label not copied.\n");
225 while (!write_record_to_block(out_block, rec)) {
226 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
228 if (!write_block_to_device(out_jcr->dcr)) {
229 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
230 out_dev->print_name(), strerror_dev(out_dev));
231 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
232 strerror_dev(out_dev));
235 if (!write_block_to_device(out_jcr->dcr)) {
236 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
237 out_dev->print_name(), strerror_dev(out_dev));
238 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
239 strerror_dev(out_dev));
243 Pmsg0(000, "EOM label not copied.\n");
245 case EOT_LABEL: /* end of all tapes */
246 Pmsg0(000, "EOT label not copied.\n");
255 while (!write_record_to_block(out_block, rec)) {
256 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
258 if (!write_block_to_device(out_jcr->dcr)) {
259 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
260 out_dev->print_name(), strerror_dev(out_dev));
261 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
262 strerror_dev(out_dev));
270 /* Dummies to replace askdir.c */
271 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) { return 1;}
272 bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
273 bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
274 bool dir_create_jobmedia_record(DCR *dcr) { return 1; }
275 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
276 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
277 bool dir_send_job_status(JCR *jcr) {return 1;}
280 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
282 DEVICE *dev = dcr->dev;
283 fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
284 dcr->VolumeName, dev->print_name());