]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
- Attempt to fix DVD writing by eliminating a number of the
[bacula/bacula] / bacula / src / stored / bcopy.c
1 /*
2  *
3  *  Program to copy a Bacula from one volume to another.
4  *
5  *   Kern E. Sibbald, October 2002
6  *
7  *
8  *   Version $Id$
9  */
10 /*
11    Copyright (C) 2002-2005 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License
15    version 2 as ammended with additional clauses defined in the
16    file LICENSE in the main source directory.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
21    the file LICENSE for additional details.
22
23  */
24
25 #include "bacula.h"
26 #include "stored.h"
27
28 /* Dummy functions */
29 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
30
31 /* Forward referenced functions */
32 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
33
34
35 /* Global variables */
36 static DEVICE *in_dev = NULL;
37 static DEVICE *out_dev = NULL;
38 static JCR *in_jcr;                    /* input jcr */
39 static JCR *out_jcr;                   /* output jcr */
40 static BSR *bsr = NULL;
41 static const char *wd = "/tmp";
42 static int list_records = 0;
43 static uint32_t records = 0;
44 static uint32_t jobs = 0;
45 static DEV_BLOCK *out_block;
46
47 #define CONFIG_FILE "bacula-sd.conf"
48 char *configfile = NULL;
49 STORES *me = NULL;                    /* our Global resource */
50 bool forge_on = false;                /* proceed inspite of I/O errors */
51 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
52 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
53
54
55 static void usage()
56 {
57    fprintf(stderr, _(
58 "Copyright (C) 2002-2005 Kern Sibbald.\n"
59 "\nVersion: " VERSION " (" BDATE ")\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 configuration file\n"
63 "       -d <nn>           set debug level to nn\n"
64 "       -i                specify input Volume names (separated by |)\n"
65 "       -o                specify output Volume names (separated by |)\n"
66 "       -p                proceed inspite of errors\n"
67 "       -v                verbose\n"
68 "       -w <dir>          specify working directory (default /tmp)\n"
69 "       -?                print this message\n\n"));
70    exit(1);
71 }
72
73 int main (int argc, char *argv[])
74 {
75    int ch;
76    char *iVolumeName = NULL;
77    char *oVolumeName = NULL;
78    bool ignore_label_errors = false;
79
80    my_name_is(argc, argv, "bcopy");
81    init_msg(NULL, NULL);
82
83    while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
84       switch (ch) {
85       case 'b':
86          bsr = parse_bsr(NULL, optarg);
87          break;
88
89       case 'c':                    /* specify config file */
90          if (configfile != NULL) {
91             free(configfile);
92          }
93          configfile = bstrdup(optarg);
94          break;
95
96       case 'd':                    /* debug level */
97          debug_level = atoi(optarg);
98          if (debug_level <= 0)
99             debug_level = 1;
100          break;
101
102       case 'i':                    /* input Volume name */
103          iVolumeName = optarg;
104          break;
105
106       case 'o':                    /* output Volume name */
107          oVolumeName = optarg;
108          break;
109
110       case 'p':
111          ignore_label_errors = true;
112          forge_on = true;
113          break;
114
115       case 'v':
116          verbose++;
117          break;
118
119       case 'w':
120          wd = optarg;
121          break;
122
123       case '?':
124       default:
125          usage();
126
127       }
128    }
129    argc -= optind;
130    argv += optind;
131
132    if (argc != 2) {
133       Pmsg0(0, _("Wrong number of arguments: \n"));
134       usage();
135    }
136
137    working_directory = wd;
138
139    if (configfile == NULL) {
140       configfile = bstrdup(CONFIG_FILE);
141    }
142
143    parse_config(configfile);
144
145    /* Setup and acquire input device for reading */
146    in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
147    if (!in_jcr) {
148       exit(1);
149    }
150    in_jcr->ignore_label_errors = ignore_label_errors;
151    in_dev = in_jcr->dcr->dev;
152    if (!in_dev) {
153       exit(1);
154    }
155
156    /* Setup output device for writing */
157    out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
158    if (!out_jcr) {
159       exit(1);
160    }
161    out_dev = out_jcr->dcr->dev;
162    if (!out_dev) {
163       exit(1);
164    }
165    /* For we must now acquire the device for writing */
166    lock_device(out_dev);
167    if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
168       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
169       unlock_device(out_dev);
170       exit(1);
171    }
172    unlock_device(out_dev);
173    if (!acquire_device_for_append(out_jcr->dcr)) {
174       free_jcr(in_jcr);
175       exit(1);
176    }
177    out_block = out_jcr->dcr->block;
178
179    read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
180    if (!write_block_to_device(out_jcr->dcr)) {
181       Pmsg0(000, _("Write of last block failed.\n"));
182    }
183
184    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
185
186    free_jcr(in_jcr);
187    free_jcr(out_jcr);
188
189    term_dev(in_dev);
190    term_dev(out_dev);
191    return 0;
192 }
193
194
195 /*
196  * read_records() calls back here for each record it gets
197  */
198 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
199 {
200    if (list_records) {
201       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
202             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
203             rec->Stream, rec->data_len);
204    }
205    /*
206     * Check for Start or End of Session Record
207     *
208     */
209    if (rec->FileIndex < 0) {
210
211       if (verbose > 1) {
212          dump_label_record(in_dcr->dev, rec, 1);
213       }
214       switch (rec->FileIndex) {
215       case PRE_LABEL:
216          Pmsg0(000, "Volume is prelabeled. This volume cannot be copied.\n");
217          return false;
218       case VOL_LABEL:
219          Pmsg0(000, "Volume label not copied.\n");
220          return true;
221       case SOS_LABEL:
222          jobs++;
223          break;
224       case EOS_LABEL:
225          while (!write_record_to_block(out_block, rec)) {
226             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
227                        rec->remainder);
228             if (!write_block_to_device(out_jcr->dcr)) {
229                Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
230                   out_dev->print_name(), strerror_dev(out_dev));
231                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
232                      strerror_dev(out_dev));
233             }
234          }
235          if (!write_block_to_device(out_jcr->dcr)) {
236             Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
237                out_dev->print_name(), strerror_dev(out_dev));
238             Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
239                   strerror_dev(out_dev));
240          }
241          break;
242       case EOM_LABEL:
243          Pmsg0(000, "EOM label not copied.\n");
244          return true;
245       case EOT_LABEL:              /* end of all tapes */
246          Pmsg0(000, "EOT label not copied.\n");
247          return true;
248       default:
249          break;
250       }
251    }
252
253    /*  Write record */
254    records++;
255    while (!write_record_to_block(out_block, rec)) {
256       Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
257                  rec->remainder);
258       if (!write_block_to_device(out_jcr->dcr)) {
259          Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
260             out_dev->print_name(), strerror_dev(out_dev));
261          Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
262                strerror_dev(out_dev));
263          break;
264       }
265    }
266    return true;
267 }
268
269
270 /* Dummies to replace askdir.c */
271 bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing) { return 1;}
272 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
273 bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
274 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
275 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
276 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
277 bool    dir_send_job_status(JCR *jcr) {return 1;}
278 VOLRES *new_volume(const char *VolumeName, DEVICE *dev) { return NULL; }
279 bool    free_volume(DEVICE *dev) { return true; }
280
281
282 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
283 {
284    DEVICE *dev = dcr->dev;
285    fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
286       dcr->VolumeName, dev->print_name());
287    getchar();
288    return true;
289 }