]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
03Dec07
[bacula/bacula] / bacula / src / stored / bcopy.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2007 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 two of the GNU 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 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 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.
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
44 /* Forward referenced functions */
45 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
46
47
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;
59
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;
66
67
68 static void usage()
69 {
70    fprintf(stderr, _(
71 PROG_COPYRIGHT
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"
80 "       -v                verbose\n"
81 "       -w <dir>          specify working directory (default /tmp)\n"
82 "       -?                print this message\n\n"), 2002, VERSION, BDATE);
83    exit(1);
84 }
85
86 int main (int argc, char *argv[])
87 {
88    int ch;
89    char *iVolumeName = NULL;
90    char *oVolumeName = NULL;
91    bool ignore_label_errors = false;
92    bool ok;
93
94    setlocale(LC_ALL, "");
95    bindtextdomain("bacula", LOCALEDIR);
96    textdomain("bacula");
97    init_stack_dump();
98
99    my_name_is(argc, argv, "bcopy");
100    init_msg(NULL, NULL);
101
102    while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
103       switch (ch) {
104       case 'b':
105          bsr = parse_bsr(NULL, optarg);
106          break;
107
108       case 'c':                    /* specify config file */
109          if (configfile != NULL) {
110             free(configfile);
111          }
112          configfile = bstrdup(optarg);
113          break;
114
115       case 'd':                    /* debug level */
116          debug_level = atoi(optarg);
117          if (debug_level <= 0)
118             debug_level = 1;
119          break;
120
121       case 'i':                    /* input Volume name */
122          iVolumeName = optarg;
123          break;
124
125       case 'o':                    /* output Volume name */
126          oVolumeName = optarg;
127          break;
128
129       case 'p':
130          ignore_label_errors = true;
131          forge_on = true;
132          break;
133
134       case 'v':
135          verbose++;
136          break;
137
138       case 'w':
139          wd = optarg;
140          break;
141
142       case '?':
143       default:
144          usage();
145
146       }
147    }
148    argc -= optind;
149    argv += optind;
150
151    if (argc != 2) {
152       Pmsg0(0, _("Wrong number of arguments: \n"));
153       usage();
154    }
155
156    OSDependentInit();
157
158    working_directory = wd;
159
160    if (configfile == NULL) {
161       configfile = bstrdup(CONFIG_FILE);
162    }
163
164    parse_config(configfile);
165
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 */
169    if (!in_jcr) {
170       exit(1);
171    }
172    in_jcr->ignore_label_errors = ignore_label_errors;
173    in_dev = in_jcr->dcr->dev;
174    if (!in_dev) {
175       exit(1);
176    }
177
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 */
181    if (!out_jcr) {
182       exit(1);
183    }
184    out_dev = out_jcr->dcr->dev;
185    if (!out_dev) {
186       exit(1);
187    }
188    Dmsg0(100, "About to acquire device for writing\n");
189    /* For we must now acquire the device for writing */
190    out_dev->r_dlock();
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);
193       out_dev->dunlock();
194       exit(1);
195    }
196    out_dev->dunlock();
197    if (!acquire_device_for_append(out_jcr->dcr)) {
198       free_jcr(in_jcr);
199       exit(1);
200    }
201    out_block = out_jcr->dcr->block;
202
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"));
207       }
208    }
209
210    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
211
212    free_jcr(in_jcr);
213    free_jcr(out_jcr);
214
215    in_dev->term();
216    out_dev->term();
217    return 0;
218 }
219
220
221 /*
222  * read_records() calls back here for each record it gets
223  */
224 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
225 {
226    if (list_records) {
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);
230    }
231    /*
232     * Check for Start or End of Session Record
233     *
234     */
235    if (rec->FileIndex < 0) {
236
237       if (verbose > 1) {
238          dump_label_record(in_dcr->dev, rec, 1);
239       }
240       switch (rec->FileIndex) {
241       case PRE_LABEL:
242          Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
243          return false;
244       case VOL_LABEL:
245          Pmsg0(000, _("Volume label not copied.\n"));
246          return true;
247       case SOS_LABEL:
248          jobs++;
249          break;
250       case EOS_LABEL:
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,
253                        rec->remainder);
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());
259                return false;
260             }
261          }
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());
267             return false;
268          }
269          return true;
270       case EOM_LABEL:
271          Pmsg0(000, _("EOM label not copied.\n"));
272          return true;
273       case EOT_LABEL:              /* end of all tapes */
274          Pmsg0(000, _("EOT label not copied.\n"));
275          return true;
276       default:
277          return true;
278       }
279    }
280
281    /*  Write record */
282    records++;
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,
285                  rec->remainder);
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());
291          return false;
292       }
293    }
294    return true;
295 }
296
297
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;}
305
306
307 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
308 {
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());
312    dev->close();
313    getchar();
314    return true;
315 }
316
317 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing)
318 {
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);
323    return 1;
324 }