2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
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
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.
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
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.
30 * Program to copy a Bacula from one volume to another.
32 * Kern E. Sibbald, October 2002
42 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
44 /* Forward referenced functions */
45 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
48 /* Global variables */
49 static DEVICE *in_dev = NULL;
50 static DEVICE *out_dev = NULL;
51 static JCR *in_jcr; /* input jcr */
52 static JCR *out_jcr; /* output jcr */
53 static BSR *bsr = NULL;
54 static const char *wd = "/tmp";
55 static int list_records = 0;
56 static uint32_t records = 0;
57 static uint32_t jobs = 0;
58 static DEV_BLOCK *out_block;
60 #define CONFIG_FILE "bacula-sd.conf"
61 char *configfile = NULL;
62 STORES *me = NULL; /* our Global resource */
63 bool forge_on = false; /* proceed inspite of I/O errors */
64 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
65 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
72 "\nVersion: %s (%s)\n\n"
73 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
74 " -b bootstrap specify a bootstrap file\n"
75 " -c <file> specify configuration file\n"
76 " -d <nn> set debug level to <nn>\n"
77 " -dt print timestamp in debug output\n"
78 " -i specify input Volume names (separated by |)\n"
79 " -o specify output Volume names (separated by |)\n"
80 " -p proceed inspite of errors\n"
82 " -w <dir> specify working directory (default /tmp)\n"
83 " -? print this message\n\n"), 2002, VERSION, BDATE);
87 int main (int argc, char *argv[])
90 char *iVolumeName = NULL;
91 char *oVolumeName = NULL;
92 bool ignore_label_errors = false;
94 setlocale(LC_ALL, "");
95 bindtextdomain("bacula", LOCALEDIR);
99 my_name_is(argc, argv, "bcopy");
100 init_msg(NULL, NULL);
102 while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
105 bsr = parse_bsr(NULL, optarg);
108 case 'c': /* specify config file */
109 if (configfile != NULL) {
112 configfile = bstrdup(optarg);
115 case 'd': /* debug level */
116 if (*optarg == 't') {
117 dbg_timestamp = true;
119 debug_level = atoi(optarg);
120 if (debug_level <= 0) {
126 case 'i': /* input Volume name */
127 iVolumeName = optarg;
130 case 'o': /* output Volume name */
131 oVolumeName = optarg;
135 ignore_label_errors = true;
157 Pmsg0(0, _("Wrong number of arguments: \n"));
163 working_directory = wd;
165 if (configfile == NULL) {
166 configfile = bstrdup(CONFIG_FILE);
169 parse_config(configfile);
171 /* Setup and acquire input device for reading */
172 Dmsg0(100, "About to setup input jcr\n");
173 in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
177 in_jcr->ignore_label_errors = ignore_label_errors;
178 in_dev = in_jcr->dcr->dev;
183 /* Setup output device for writing */
184 Dmsg0(100, "About to setup output jcr\n");
185 out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
189 out_dev = out_jcr->dcr->dev;
193 Dmsg0(100, "About to acquire device for writing\n");
194 /* For we must now acquire the device for writing */
196 if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
197 Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
202 if (!acquire_device_for_append(out_jcr->dcr)) {
206 out_block = out_jcr->dcr->block;
208 read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
209 if (!write_block_to_device(out_jcr->dcr)) {
210 Pmsg0(000, _("Write of last block failed.\n"));
213 Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
225 * read_records() calls back here for each record it gets
227 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
230 Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
231 rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
232 rec->Stream, rec->data_len);
235 * Check for Start or End of Session Record
238 if (rec->FileIndex < 0) {
241 dump_label_record(in_dcr->dev, rec, 1);
243 switch (rec->FileIndex) {
245 Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
248 Pmsg0(000, _("Volume label not copied.\n"));
254 while (!write_record_to_block(out_block, rec)) {
255 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
257 if (!write_block_to_device(out_jcr->dcr)) {
258 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
259 out_dev->print_name(), out_dev->bstrerror());
260 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
261 out_dev->bstrerror());
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());
272 Pmsg0(000, _("EOM label not copied.\n"));
274 case EOT_LABEL: /* end of all tapes */
275 Pmsg0(000, _("EOT label not copied.\n"));
284 while (!write_record_to_block(out_block, rec)) {
285 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
287 if (!write_block_to_device(out_jcr->dcr)) {
288 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
289 out_dev->print_name(), out_dev->bstrerror());
290 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
291 out_dev->bstrerror());
299 /* Dummies to replace askdir.c */
300 bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
301 bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
302 bool dir_create_jobmedia_record(DCR *dcr) { return 1; }
303 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
304 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
305 bool dir_send_job_status(JCR *jcr) {return 1;}
308 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
310 DEVICE *dev = dcr->dev;
311 fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
312 dcr->VolumeName, dev->print_name());
318 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
320 Dmsg0(100, "Fake dir_get_volume_info\n");
321 bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
322 dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
323 Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);