]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
Switch from GPLv2 to AGPLv3
[bacula/bacula] / bacula / src / stored / bcopy.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2010 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *
30  *  Program to copy a Bacula from one volume to another.
31  *
32  *   Kern E. Sibbald, October 2002
33  *
34  *
35  *   Version $Id$
36  */
37
38 #include "bacula.h"
39 #include "stored.h"
40
41 /* Dummy functions */
42 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
43 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
44
45 /* Forward referenced functions */
46 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
47 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
48
49
50 /* Global variables */
51 static DEVICE *in_dev = NULL;
52 static DEVICE *out_dev = NULL;
53 static JCR *in_jcr;                    /* input jcr */
54 static JCR *out_jcr;                   /* output jcr */
55 static BSR *bsr = NULL;
56 static const char *wd = "/tmp";
57 static bool list_records = false;
58 static uint32_t records = 0;
59 static uint32_t jobs = 0;
60 static DEV_BLOCK *out_block;
61 static SESSION_LABEL sessrec;
62
63 static CONFIG *config;
64 #define CONFIG_FILE "bacula-sd.conf"
65 char *configfile = NULL;
66 STORES *me = NULL;                    /* our Global resource */
67 bool forge_on = false;                /* proceed inspite of I/O errors */
68 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
69 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
70
71
72 static void usage()
73 {
74    fprintf(stderr, _(
75 PROG_COPYRIGHT
76 "\nVersion: %s (%s)\n\n"
77 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
78 "       -b bootstrap      specify a bootstrap file\n"
79 "       -c <file>         specify a Storage configuration file\n"
80 "       -d <nn>           set debug level to <nn>\n"
81 "       -dt               print timestamp in debug output\n"
82 "       -i                specify input Volume names (separated by |)\n"
83 "       -o                specify output Volume names (separated by |)\n"
84 "       -p                proceed inspite of errors\n"
85 "       -v                verbose\n"
86 "       -w <dir>          specify working directory (default /tmp)\n"
87 "       -?                print this message\n\n"), 2002, VERSION, BDATE);
88    exit(1);
89 }
90
91 int main (int argc, char *argv[])
92 {
93    int ch;
94    char *iVolumeName = NULL;
95    char *oVolumeName = NULL;
96    bool ignore_label_errors = false;
97    bool ok;
98
99    setlocale(LC_ALL, "");
100    bindtextdomain("bacula", LOCALEDIR);
101    textdomain("bacula");
102    init_stack_dump();
103
104    my_name_is(argc, argv, "bcopy");
105    lmgr_init_thread();
106    init_msg(NULL, NULL);
107
108    while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
109       switch (ch) {
110       case 'b':
111          bsr = parse_bsr(NULL, optarg);
112          break;
113
114       case 'c':                    /* specify config file */
115          if (configfile != NULL) {
116             free(configfile);
117          }
118          configfile = bstrdup(optarg);
119          break;
120
121       case 'd':                    /* debug level */
122          if (*optarg == 't') {
123             dbg_timestamp = true;
124          } else {
125             debug_level = atoi(optarg);
126             if (debug_level <= 0) {
127                debug_level = 1;
128             }
129          }
130          break;
131
132       case 'i':                    /* input Volume name */
133          iVolumeName = optarg;
134          break;
135
136       case 'o':                    /* output Volume name */
137          oVolumeName = optarg;
138          break;
139
140       case 'p':
141          ignore_label_errors = true;
142          forge_on = true;
143          break;
144
145       case 'v':
146          verbose++;
147          break;
148
149       case 'w':
150          wd = optarg;
151          break;
152
153       case '?':
154       default:
155          usage();
156
157       }
158    }
159    argc -= optind;
160    argv += optind;
161
162    if (argc != 2) {
163       Pmsg0(0, _("Wrong number of arguments: \n"));
164       usage();
165    }
166
167    OSDependentInit();
168
169    working_directory = wd;
170
171    if (configfile == NULL) {
172       configfile = bstrdup(CONFIG_FILE);
173    }
174
175    config = new_config_parser();
176    parse_sd_config(config, configfile, M_ERROR_TERM);
177
178    /* Setup and acquire input device for reading */
179    Dmsg0(100, "About to setup input jcr\n");
180    in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
181    if (!in_jcr) {
182       exit(1);
183    }
184    in_jcr->ignore_label_errors = ignore_label_errors;
185    in_dev = in_jcr->dcr->dev;
186    if (!in_dev) {
187       exit(1);
188    }
189
190    /* Setup output device for writing */
191    Dmsg0(100, "About to setup output jcr\n");
192    out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
193    if (!out_jcr) {
194       exit(1);
195    }
196    out_dev = out_jcr->dcr->dev;
197    if (!out_dev) {
198       exit(1);
199    }
200    Dmsg0(100, "About to acquire device for writing\n");
201    /* For we must now acquire the device for writing */
202    out_dev->r_dlock();
203    if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
204       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
205       out_dev->dunlock();
206       exit(1);
207    }
208    out_dev->dunlock();
209    if (!acquire_device_for_append(out_jcr->dcr)) {
210       free_jcr(in_jcr);
211       exit(1);
212    }
213    out_block = out_jcr->dcr->block;
214
215    ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
216
217    if (ok || out_dev->can_write()) {
218       if (!write_block_to_device(out_jcr->dcr)) {
219          Pmsg0(000, _("Write of last block failed.\n"));
220       }
221    }
222
223    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
224
225    free_jcr(in_jcr);
226    free_jcr(out_jcr);
227
228    in_dev->term();
229    out_dev->term();
230    return 0;
231 }
232
233
234 /*
235  * read_records() calls back here for each record it gets
236  */
237 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
238 {
239    if (list_records) {
240       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
241             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
242             rec->Stream, rec->data_len);
243    }
244    /*
245     * Check for Start or End of Session Record
246     *
247     */
248    if (rec->FileIndex < 0) {
249       get_session_record(in_dcr->dev, rec, &sessrec);
250
251       if (verbose > 1) {
252          dump_label_record(in_dcr->dev, rec, 1);
253       }
254       switch (rec->FileIndex) {
255       case PRE_LABEL:
256          Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
257          return false;
258       case VOL_LABEL:
259          Pmsg0(000, _("Volume label not copied.\n"));
260          return true;
261       case SOS_LABEL:
262          if (bsr && rec->match_stat < 1) {
263             /* Skipping record, because does not match BSR filter */
264             if (verbose) {
265              Pmsg0(-1, _("Copy skipped. Record does not match BSR filter.\n"));
266             }
267          } else {
268             jobs++;
269          }
270          break;
271       case EOS_LABEL:
272          if (bsr && rec->match_stat < 1) {
273             /* Skipping record, because does not match BSR filter */
274            return true;
275         }
276          while (!write_record_to_block(out_block, rec)) {
277             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
278                        rec->remainder);
279             if (!write_block_to_device(out_jcr->dcr)) {
280                Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
281                   out_dev->print_name(), out_dev->bstrerror());
282                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
283                      out_dev->bstrerror());
284                return false;
285             }
286          }
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());
292             return false;
293          }
294          return true;
295       case EOM_LABEL:
296          Pmsg0(000, _("EOM label not copied.\n"));
297          return true;
298       case EOT_LABEL:              /* end of all tapes */
299          Pmsg0(000, _("EOT label not copied.\n"));
300          return true;
301       default:
302          return true;
303       }
304    }
305
306    /*  Write record */
307    if (bsr && rec->match_stat < 1) {
308       /* Skipping record, because does not match BSR filter */
309       return true;
310    }
311    records++;
312    while (!write_record_to_block(out_block, rec)) {
313       Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
314                  rec->remainder);
315       if (!write_block_to_device(out_jcr->dcr)) {
316          Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
317             out_dev->print_name(), out_dev->bstrerror());
318          Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
319                out_dev->bstrerror());
320          return false;
321       }
322    }
323    return true;
324 }
325
326 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
327 {
328    const char *rtype;
329    memset(sessrec, 0, sizeof(sessrec));
330    switch (rec->FileIndex) {
331    case PRE_LABEL:
332       rtype = _("Fresh Volume Label");
333       break;
334    case VOL_LABEL:
335       rtype = _("Volume Label");
336       unser_volume_label(dev, rec);
337       break;
338    case SOS_LABEL:
339       rtype = _("Begin Job Session");
340       unser_session_label(sessrec, rec);
341       break;
342    case EOS_LABEL:
343       rtype = _("End Job Session");
344       unser_session_label(sessrec, rec);
345       break;
346    case 0:
347    case EOM_LABEL:
348       rtype = _("End of Medium");
349       break;
350    default:
351       rtype = _("Unknown");
352       break;
353    }
354    Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
355          rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
356    if (verbose) {
357       Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
358             rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
359    }
360 }
361
362
363 /* Dummies to replace askdir.c */
364 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
365 bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
366 bool    dir_create_jobmedia_record(DCR *dcr, bool zero) { return 1; }
367 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
368 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
369 bool    dir_send_job_status(JCR *jcr) {return 1;}
370
371
372 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
373 {
374    DEVICE *dev = dcr->dev;
375    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
376       dcr->VolumeName, dev->print_name());
377    dev->close();
378    getchar();
379    return true;
380 }
381
382 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing)
383 {
384    Dmsg0(100, "Fake dir_get_volume_info\n");
385    dcr->setVolCatName(dcr->VolumeName);
386    dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
387    Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatParts);
388    return 1;
389 }