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