2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2012 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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
40 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
41 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
43 /* Forward referenced functions */
44 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
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 bool list_records = false;
56 static uint32_t records = 0;
57 static uint32_t jobs = 0;
58 static DEV_BLOCK *out_block;
59 static SESSION_LABEL sessrec;
61 static CONFIG *config;
62 #define CONFIG_FILE "bacula-sd.conf"
63 char *configfile = NULL;
64 STORES *me = NULL; /* our Global resource */
65 bool forge_on = false; /* proceed inspite of I/O errors */
66 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
67 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
74 "\nVersion: %s (%s)\n\n"
75 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
76 " -b bootstrap specify a bootstrap file\n"
77 " -c <file> specify a Storage configuration file\n"
78 " -d <nn> set debug level to <nn>\n"
79 " -dt print timestamp in debug output\n"
80 " -i specify input Volume names (separated by |)\n"
81 " -o specify output Volume names (separated by |)\n"
82 " -p proceed inspite of errors\n"
84 " -w <dir> specify working directory (default /tmp)\n"
85 " -? print this message\n\n"), 2002, VERSION, BDATE);
89 int main (int argc, char *argv[])
92 char *iVolumeName = NULL;
93 char *oVolumeName = NULL;
94 bool ignore_label_errors = false;
97 setlocale(LC_ALL, "");
98 bindtextdomain("bacula", LOCALEDIR);
102 my_name_is(argc, argv, "bcopy");
104 init_msg(NULL, NULL);
106 while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
109 bsr = parse_bsr(NULL, optarg);
112 case 'c': /* specify config file */
113 if (configfile != NULL) {
116 configfile = bstrdup(optarg);
119 case 'd': /* debug level */
120 if (*optarg == 't') {
121 dbg_timestamp = true;
123 debug_level = atoi(optarg);
124 if (debug_level <= 0) {
130 case 'i': /* input Volume name */
131 iVolumeName = optarg;
134 case 'o': /* output Volume name */
135 oVolumeName = optarg;
139 ignore_label_errors = true;
161 Pmsg0(0, _("Wrong number of arguments: \n"));
167 working_directory = wd;
169 if (configfile == NULL) {
170 configfile = bstrdup(CONFIG_FILE);
173 config = new_config_parser();
174 parse_sd_config(config, configfile, M_ERROR_TERM);
176 /* Setup and acquire input device for reading */
177 Dmsg0(100, "About to setup input jcr\n");
178 in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
182 in_jcr->ignore_label_errors = ignore_label_errors;
183 in_dev = in_jcr->dcr->dev;
188 /* Setup output device for writing */
189 Dmsg0(100, "About to setup output jcr\n");
190 out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
194 out_dev = out_jcr->dcr->dev;
198 Dmsg0(100, "About to acquire device for writing\n");
199 /* For we must now acquire the device for writing */
201 if (!out_dev->open(out_jcr->dcr, OPEN_READ_WRITE)) {
202 Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
207 if (!acquire_device_for_append(out_jcr->dcr)) {
211 out_block = out_jcr->dcr->block;
213 ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
215 if (ok || out_dev->can_write()) {
216 if (!out_jcr->dcr->write_block_to_device()) {
217 Pmsg0(000, _("Write of last block failed.\n"));
221 Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
233 * read_records() calls back here for each record it gets
235 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
238 Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
239 rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
240 rec->Stream, rec->data_len);
243 * Check for Start or End of Session Record
246 if (rec->FileIndex < 0) {
247 get_session_record(in_dcr->dev, rec, &sessrec);
250 dump_label_record(in_dcr->dev, rec, 1);
252 switch (rec->FileIndex) {
254 Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
257 Pmsg0(000, _("Volume label not copied.\n"));
260 if (bsr && rec->match_stat < 1) {
261 /* Skipping record, because does not match BSR filter */
263 Pmsg0(-1, _("Copy skipped. Record does not match BSR filter.\n"));
270 if (bsr && rec->match_stat < 1) {
271 /* Skipping record, because does not match BSR filter */
274 while (!write_record_to_block(out_jcr->dcr, rec)) {
275 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
277 if (!out_jcr->dcr->write_block_to_device()) {
278 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
279 out_dev->print_name(), out_dev->bstrerror());
280 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
281 out_dev->bstrerror());
285 if (!out_jcr->dcr->write_block_to_device()) {
286 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
287 out_dev->print_name(), out_dev->bstrerror());
288 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
289 out_dev->bstrerror());
294 Pmsg0(000, _("EOM label not copied.\n"));
296 case EOT_LABEL: /* end of all tapes */
297 Pmsg0(000, _("EOT label not copied.\n"));
305 if (bsr && rec->match_stat < 1) {
306 /* Skipping record, because does not match BSR filter */
310 while (!write_record_to_block(out_jcr->dcr, rec)) {
311 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
313 if (!out_jcr->dcr->write_block_to_device()) {
314 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
315 out_dev->print_name(), out_dev->bstrerror());
316 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
317 out_dev->bstrerror());
324 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
327 memset(sessrec, 0, sizeof(SESSION_LABEL));
328 switch (rec->FileIndex) {
330 rtype = _("Fresh Volume Label");
333 rtype = _("Volume Label");
334 unser_volume_label(dev, rec);
337 rtype = _("Begin Job Session");
338 unser_session_label(sessrec, rec);
341 rtype = _("End Job Session");
342 unser_session_label(sessrec, rec);
346 rtype = _("End of Medium");
349 rtype = _("Unknown");
352 Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
353 rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
355 Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
356 rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
361 /* Dummies to replace askdir.c */
362 bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
363 bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
364 bool dir_create_jobmedia_record(DCR *dcr, bool zero) { return 1; }
365 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
366 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
367 bool dir_send_job_status(JCR *jcr) {return 1;}
370 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
372 DEVICE *dev = dcr->dev;
373 fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
374 dcr->VolumeName, dev->print_name());
380 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
382 Dmsg0(100, "Fake dir_get_volume_info\n");
383 dcr->setVolCatName(dcr->VolumeName);
384 dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
385 Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatParts);