2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Program to copy a Bacula from one volume to another.
23 * Kern E. Sibbald, October 2002
29 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
31 /* Forward referenced functions */
32 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
33 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
36 /* Global variables */
37 static DEVICE *in_dev = NULL;
38 static DEVICE *out_dev = NULL;
39 static JCR *in_jcr; /* input jcr */
40 static JCR *out_jcr; /* output jcr */
41 static BSR *bsr = NULL;
42 static const char *wd = "/tmp";
43 static bool list_records = false;
44 static uint32_t records = 0;
45 static uint32_t jobs = 0;
46 static DEV_BLOCK *out_block;
47 static SESSION_LABEL sessrec;
49 static CONFIG *config;
50 #define CONFIG_FILE "bacula-sd.conf"
53 char *configfile = NULL;
59 "\n%sVersion: %s (%s)\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 a Storage configuration file\n"
63 " -d <nn> set debug level to <nn>\n"
64 " -dt print timestamp in debug output\n"
65 " -i specify input Volume names (separated by |)\n"
66 " -o specify output Volume names (separated by |)\n"
67 " -p proceed inspite of errors\n"
69 " -w <dir> specify working directory (default /tmp)\n"
70 " -? print this message\n\n"), 2002, "", VERSION, BDATE);
74 int main (int argc, char *argv[])
77 char *iVolumeName = NULL;
78 char *oVolumeName = NULL;
79 bool ignore_label_errors = false;
81 BtoolsAskDirHandler askdir_handler;
83 init_askdir_handler(&askdir_handler);
84 setlocale(LC_ALL, "");
85 bindtextdomain("bacula", LOCALEDIR);
89 my_name_is(argc, argv, "bcopy");
93 while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
96 bsr = parse_bsr(NULL, optarg);
99 case 'c': /* specify config file */
100 if (configfile != NULL) {
103 configfile = bstrdup(optarg);
106 case 'd': /* debug level */
107 if (*optarg == 't') {
108 dbg_timestamp = true;
110 debug_level = atoi(optarg);
111 if (debug_level <= 0) {
117 case 'i': /* input Volume name */
118 iVolumeName = optarg;
121 case 'o': /* output Volume name */
122 oVolumeName = optarg;
126 ignore_label_errors = true;
148 Pmsg0(0, _("Wrong number of arguments: \n"));
154 working_directory = wd;
156 if (configfile == NULL) {
157 configfile = bstrdup(CONFIG_FILE);
160 config = New(CONFIG());
161 parse_sd_config(config, configfile, M_ERROR_TERM);
163 load_sd_plugins(me->plugin_directory);
165 /* Setup and acquire input device for reading */
166 Dmsg0(100, "About to setup input jcr\n");
167 in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, SD_READ, true/*read dedup data*/); /* read device */
171 in_jcr->ignore_label_errors = ignore_label_errors;
172 in_dev = in_jcr->dcr->dev;
177 /* Setup output device for writing */
178 Dmsg0(100, "About to setup output jcr\n");
179 out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, SD_APPEND); /* no acquire */
183 out_dev = out_jcr->dcr->dev;
187 Dmsg0(100, "About to acquire device for writing\n");
188 /* For we must now acquire the device for writing */
189 out_dev->rLock(false);
190 if (!out_dev->open_device(out_jcr->dcr, OPEN_READ_WRITE)) {
191 Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
196 if (!acquire_device_for_append(out_jcr->dcr)) {
200 out_block = out_jcr->dcr->block;
202 ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
204 if (ok || out_dev->can_write()) {
205 if (!out_jcr->dcr->write_final_block_to_device()) {
206 Pmsg0(000, _("Write of last block failed.\n"));
210 Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
223 * read_records() calls back here for each record it gets
225 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
228 Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
229 rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
230 rec->Stream, rec->data_len);
233 * Check for Start or End of Session Record
236 if (rec->FileIndex < 0) {
237 get_session_record(in_dcr->dev, rec, &sessrec);
240 dump_label_record(in_dcr->dev, rec, 1/*verbose*/, false/*check err*/);
242 switch (rec->FileIndex) {
244 Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
247 Pmsg0(000, _("Volume label not copied.\n"));
250 if (bsr && rec->match_stat < 1) {
251 /* Skipping record, because does not match BSR filter */
253 Pmsg0(-1, _("Copy skipped. Record does not match BSR filter.\n"));
260 if (bsr && rec->match_stat < 1) {
261 /* Skipping record, because does not match BSR filter */
264 while (!write_record_to_block(out_jcr->dcr, rec)) {
265 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
267 if (!out_jcr->dcr->write_block_to_device()) {
268 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
269 out_dev->print_name(), out_dev->bstrerror());
270 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
271 out_dev->bstrerror());
275 if (!out_jcr->dcr->write_block_to_device()) {
276 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
277 out_dev->print_name(), out_dev->bstrerror());
278 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
279 out_dev->bstrerror());
284 Pmsg0(000, _("EOM label not copied.\n"));
286 case EOT_LABEL: /* end of all tapes */
287 Pmsg0(000, _("EOT label not copied.\n"));
295 if (bsr && rec->match_stat < 1) {
296 /* Skipping record, because does not match BSR filter */
300 while (!write_record_to_block(out_jcr->dcr, rec)) {
301 Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
303 if (!out_jcr->dcr->write_block_to_device()) {
304 Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
305 out_dev->print_name(), out_dev->bstrerror());
306 Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
307 out_dev->bstrerror());
314 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
317 memset(sessrec, 0, sizeof(SESSION_LABEL));
318 switch (rec->FileIndex) {
320 rtype = _("Fresh Volume Label");
323 rtype = _("Volume Label");
324 unser_volume_label(dev, rec);
327 rtype = _("Begin Job Session");
328 unser_session_label(sessrec, rec);
331 rtype = _("End Job Session");
332 unser_session_label(sessrec, rec);
336 rtype = _("End of Medium");
339 rtype = _("Unknown");
342 Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
343 rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
345 Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
346 rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);