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 as
15 published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
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 GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public
24 License along with this program; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
34 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
36 /* Forward referenced functions */
37 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
40 /* Global variables */
41 static DEVICE *in_dev = NULL;
42 static DEVICE *out_dev = NULL;
43 static JCR *in_jcr; /* input jcr */
44 static JCR *out_jcr; /* output jcr */
45 static BSR *bsr = NULL;
46 static const char *wd = "/tmp";
47 static int list_records = 0;
48 static uint32_t records = 0;
49 static uint32_t jobs = 0;
50 static DEV_BLOCK *out_block;
52 #define CONFIG_FILE "bacula-sd.conf"
54 STORES *me = NULL; /* our Global resource */
55 bool forge_on = false; /* proceed inspite of I/O errors */
56 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
57 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
63 "Copyright (C) 2002-2005 Kern Sibbald.\n"
64 "\nVersion: " VERSION " (" BDATE ")\n\n"
65 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
66 " -b bootstrap specify a bootstrap file\n"
67 " -c <file> specify configuration file\n"
68 " -d <nn> set debug level to nn\n"
69 " -i specify input Volume names (separated by |)\n"
70 " -o specify output Volume names (separated by |)\n"
71 " -p proceed inspite of errors\n"
73 " -w <dir> specify working directory (default /tmp)\n"
74 " -? print this message\n\n"));
78 int main (int argc, char *argv[])
81 char *iVolumeName = NULL;
82 char *oVolumeName = NULL;
83 bool ignore_label_errors = false;
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"));
142 working_directory = wd;
144 if (configfile == NULL) {
145 configfile = bstrdup(CONFIG_FILE);
148 parse_config(configfile);
150 /* Setup and acquire input device for reading */
151 in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
155 in_jcr->ignore_label_errors = ignore_label_errors;
156 in_dev = in_jcr->dcr->dev;
161 /* Setup output device for writing */
162 out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
166 out_dev = out_jcr->dcr->dev;
170 /* For we must now acquire the device for writing */
171 lock_device(out_dev);
172 if (open_dev(out_dev, out_jcr->dcr->VolumeName, OPEN_READ_WRITE) < 0) {
173 Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
174 unlock_device(out_dev);
177 unlock_device(out_dev);
178 if (!acquire_device_for_append(out_jcr->dcr)) {
182 out_block = out_jcr->dcr->block;
184 read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
185 if (!write_block_to_device(out_jcr->dcr)) {
186 Pmsg0(000, _("Write of last block failed.\n"));
189 Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
201 * read_records() calls back here for each record it gets
203 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
206 Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
207 rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
208 rec->Stream, rec->data_len);
211 * Check for Start or End of Session Record
214 if (rec->FileIndex < 0) {
217 dump_label_record(in_dcr->dev, rec, 1);
219 switch (rec->FileIndex) {
221 Pmsg0(000, "Volume is prelabeled. This volume cannot be copied.\n");
224 Pmsg0(000, "Volume label not copied.\n");
230 while (!write_record_to_block(out_block, rec)) {
231 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
233 if (!write_block_to_device(out_jcr->dcr)) {
234 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
235 out_dev->print_name(), strerror_dev(out_dev));
236 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
237 strerror_dev(out_dev));
240 if (!write_block_to_device(out_jcr->dcr)) {
241 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
242 out_dev->print_name(), strerror_dev(out_dev));
243 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
244 strerror_dev(out_dev));
248 Pmsg0(000, "EOM label not copied.\n");
250 case EOT_LABEL: /* end of all tapes */
251 Pmsg0(000, "EOT label not copied.\n");
260 while (!write_record_to_block(out_block, rec)) {
261 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
263 if (!write_block_to_device(out_jcr->dcr)) {
264 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
265 out_dev->print_name(), strerror_dev(out_dev));
266 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
267 strerror_dev(out_dev));
275 /* Dummies to replace askdir.c */
276 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) { return 1;}
277 bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
278 bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
279 bool dir_create_jobmedia_record(DCR *dcr) { return 1; }
280 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
281 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
282 bool dir_send_job_status(JCR *jcr) {return 1;}
285 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
287 DEVICE *dev = dcr->dev;
288 fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
289 dcr->VolumeName, dev->print_name());