]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
11Apr07
[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 plus additions
11    that are listed 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
93    setlocale(LC_ALL, "");
94    bindtextdomain("bacula", LOCALEDIR);
95    textdomain("bacula");
96    init_stack_dump();
97
98    my_name_is(argc, argv, "bcopy");
99    init_msg(NULL, NULL);
100
101    while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
102       switch (ch) {
103       case 'b':
104          bsr = parse_bsr(NULL, optarg);
105          break;
106
107       case 'c':                    /* specify config file */
108          if (configfile != NULL) {
109             free(configfile);
110          }
111          configfile = bstrdup(optarg);
112          break;
113
114       case 'd':                    /* debug level */
115          debug_level = atoi(optarg);
116          if (debug_level <= 0)
117             debug_level = 1;
118          break;
119
120       case 'i':                    /* input Volume name */
121          iVolumeName = optarg;
122          break;
123
124       case 'o':                    /* output Volume name */
125          oVolumeName = optarg;
126          break;
127
128       case 'p':
129          ignore_label_errors = true;
130          forge_on = true;
131          break;
132
133       case 'v':
134          verbose++;
135          break;
136
137       case 'w':
138          wd = optarg;
139          break;
140
141       case '?':
142       default:
143          usage();
144
145       }
146    }
147    argc -= optind;
148    argv += optind;
149
150    if (argc != 2) {
151       Pmsg0(0, _("Wrong number of arguments: \n"));
152       usage();
153    }
154
155    OSDependentInit();
156
157    working_directory = wd;
158
159    if (configfile == NULL) {
160       configfile = bstrdup(CONFIG_FILE);
161    }
162
163    parse_config(configfile);
164
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, 1); /* read device */
168    if (!in_jcr) {
169       exit(1);
170    }
171    in_jcr->ignore_label_errors = ignore_label_errors;
172    in_dev = in_jcr->dcr->dev;
173    if (!in_dev) {
174       exit(1);
175    }
176
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, 0); /* no acquire */
180    if (!out_jcr) {
181       exit(1);
182    }
183    out_dev = out_jcr->dcr->dev;
184    if (!out_dev) {
185       exit(1);
186    }
187    Dmsg0(100, "About to acquire device for writing\n");
188    /* For we must now acquire the device for writing */
189    out_dev->r_dlock();
190    if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
191       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
192       out_dev->dunlock();
193       exit(1);
194    }
195    out_dev->dunlock();
196    if (!acquire_device_for_append(out_jcr->dcr)) {
197       free_jcr(in_jcr);
198       exit(1);
199    }
200    out_block = out_jcr->dcr->block;
201
202    read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
203    if (!write_block_to_device(out_jcr->dcr)) {
204       Pmsg0(000, _("Write of last block failed.\n"));
205    }
206
207    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
208
209    free_jcr(in_jcr);
210    free_jcr(out_jcr);
211
212    in_dev->term();
213    out_dev->term();
214    return 0;
215 }
216
217
218 /*
219  * read_records() calls back here for each record it gets
220  */
221 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
222 {
223    if (list_records) {
224       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
225             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
226             rec->Stream, rec->data_len);
227    }
228    /*
229     * Check for Start or End of Session Record
230     *
231     */
232    if (rec->FileIndex < 0) {
233
234       if (verbose > 1) {
235          dump_label_record(in_dcr->dev, rec, 1);
236       }
237       switch (rec->FileIndex) {
238       case PRE_LABEL:
239          Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
240          return false;
241       case VOL_LABEL:
242          Pmsg0(000, _("Volume label not copied.\n"));
243          return true;
244       case SOS_LABEL:
245          jobs++;
246          break;
247       case EOS_LABEL:
248          while (!write_record_to_block(out_block, rec)) {
249             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
250                        rec->remainder);
251             if (!write_block_to_device(out_jcr->dcr)) {
252                Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
253                   out_dev->print_name(), out_dev->bstrerror());
254                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
255                      out_dev->bstrerror());
256             }
257          }
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(), out_dev->bstrerror());
261             Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
262                   out_dev->bstrerror());
263          }
264          break;
265       case EOM_LABEL:
266          Pmsg0(000, _("EOM label not copied.\n"));
267          return true;
268       case EOT_LABEL:              /* end of all tapes */
269          Pmsg0(000, _("EOT label not copied.\n"));
270          return true;
271       default:
272          break;
273       }
274    }
275
276    /*  Write record */
277    records++;
278    while (!write_record_to_block(out_block, rec)) {
279       Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
280                  rec->remainder);
281       if (!write_block_to_device(out_jcr->dcr)) {
282          Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
283             out_dev->print_name(), out_dev->bstrerror());
284          Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
285                out_dev->bstrerror());
286          break;
287       }
288    }
289    return true;
290 }
291
292
293 /* Dummies to replace askdir.c */
294 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
295 bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
296 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
297 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
298 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
299 bool    dir_send_job_status(JCR *jcr) {return 1;}
300
301
302 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
303 {
304    DEVICE *dev = dcr->dev;
305    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
306       dcr->VolumeName, dev->print_name());
307    dev->close();
308    getchar();
309    return true;
310 }
311
312 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing)
313 {
314    Dmsg0(100, "Fake dir_get_volume_info\n");
315    bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
316    dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
317    Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);
318    return 1;
319 }