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