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 " -i specify input Volume names (separated by |)\n"
78 " -o specify output Volume names (separated by |)\n"
79 " -p proceed inspite of errors\n"
81 " -w <dir> specify working directory (default /tmp)\n"
82 " -? print this message\n\n"), 2002, VERSION, BDATE);
86 int main (int argc, char *argv[])
89 char *iVolumeName = NULL;
90 char *oVolumeName = NULL;
91 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 debug_level = atoi(optarg);
117 if (debug_level <= 0)
121 case 'i': /* input Volume name */
122 iVolumeName = optarg;
125 case 'o': /* output Volume name */
126 oVolumeName = optarg;
130 ignore_label_errors = true;
152 Pmsg0(0, _("Wrong number of arguments: \n"));
158 working_directory = wd;
160 if (configfile == NULL) {
161 configfile = bstrdup(CONFIG_FILE);
164 parse_config(configfile);
166 /* Setup and acquire input device for reading */
167 Dmsg0(100, "About to setup input jcr\n");
168 in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
172 in_jcr->ignore_label_errors = ignore_label_errors;
173 in_dev = in_jcr->dcr->dev;
178 /* Setup output device for writing */
179 Dmsg0(100, "About to setup output jcr\n");
180 out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
184 out_dev = out_jcr->dcr->dev;
188 Dmsg0(100, "About to acquire device for writing\n");
189 /* For we must now acquire the device for writing */
191 if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
192 Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
197 if (!acquire_device_for_append(out_jcr->dcr)) {
201 out_block = out_jcr->dcr->block;
203 ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
204 if (ok || out_dev->can_write()) {
205 if (!write_block_to_device(out_jcr->dcr)) {
206 Pmsg0(000, _("Write of last block failed.\n"));
210 Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
222 * read_records() calls back here for each record it gets
224 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
227 Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
228 rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
229 rec->Stream, rec->data_len);
232 * Check for Start or End of Session Record
235 if (rec->FileIndex < 0) {
238 dump_label_record(in_dcr->dev, rec, 1);
240 switch (rec->FileIndex) {
242 Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
245 Pmsg0(000, _("Volume label not copied.\n"));
251 while (!write_record_to_block(out_block, rec)) {
252 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
254 if (!write_block_to_device(out_jcr->dcr)) {
255 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
256 out_dev->print_name(), out_dev->bstrerror());
257 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
258 out_dev->bstrerror());
262 if (!write_block_to_device(out_jcr->dcr)) {
263 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
264 out_dev->print_name(), out_dev->bstrerror());
265 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
266 out_dev->bstrerror());
271 Pmsg0(000, _("EOM label not copied.\n"));
273 case EOT_LABEL: /* end of all tapes */
274 Pmsg0(000, _("EOT label not copied.\n"));
283 while (!write_record_to_block(out_block, rec)) {
284 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
286 if (!write_block_to_device(out_jcr->dcr)) {
287 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
288 out_dev->print_name(), out_dev->bstrerror());
289 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
290 out_dev->bstrerror());
298 /* Dummies to replace askdir.c */
299 bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
300 bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
301 bool dir_create_jobmedia_record(DCR *dcr) { return 1; }
302 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
303 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
304 bool dir_send_job_status(JCR *jcr) {return 1;}
307 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
309 DEVICE *dev = dcr->dev;
310 fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
311 dcr->VolumeName, dev->print_name());
317 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
319 Dmsg0(100, "Fake dir_get_volume_info\n");
320 bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
321 dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
322 Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);