]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
d4a511198796c66c98f06b003166f9f4d9601b9e
[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-2004 Kern Sibbald and John Walker
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(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, 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 bool forge_on = true;
52
53
54 static void usage()
55 {
56    fprintf(stderr, _(
57 "Copyright (C) 2002-2004 Kern Sibbald and John Walker.\n"
58 "\nVersion: " VERSION " (" BDATE ")\n\n"
59 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
60 "       -b bootstrap      specify a bootstrap file\n"
61 "       -c <file>         specify configuration file\n"
62 "       -d <nn>           set debug level to nn\n"
63 "       -i                specify input Volume names (separated by |)\n"
64 "       -o                specify output Volume names (separated by |)\n"
65 "       -p                proceed inspite of errors\n"
66 "       -v                verbose\n"
67 "       -w <dir>          specify working directory (default /tmp)\n"
68 "       -?                print this message\n\n"));
69    exit(1);
70 }
71
72 int main (int argc, char *argv[])
73 {
74    int ch;
75    char *iVolumeName = NULL;
76    char *oVolumeName = NULL;
77    bool ignore_label_errors = false;
78
79    my_name_is(argc, argv, "bcopy");
80    init_msg(NULL, NULL);
81
82    while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
83       switch (ch) {
84       case 'b':
85          bsr = parse_bsr(NULL, optarg);
86          break;
87
88       case 'c':                    /* specify config file */
89          if (configfile != NULL) {
90             free(configfile);
91          }
92          configfile = bstrdup(optarg);
93          break;
94
95       case 'd':                    /* debug level */
96          debug_level = atoi(optarg);
97          if (debug_level <= 0)
98             debug_level = 1; 
99          break;
100
101       case 'i':                    /* input Volume name */
102          iVolumeName = optarg;
103          break;
104
105       case 'o':                    /* output Volume name */
106          oVolumeName = optarg;
107          break;
108
109       case 'p':
110          ignore_label_errors = true;
111          forge_on = true;
112          break;
113   
114       case 'v':
115          verbose++;
116          break;
117
118       case 'w':
119          wd = optarg;
120          break;
121
122       case '?':
123       default:
124          usage();
125
126       }  
127    }
128    argc -= optind;
129    argv += optind;
130
131    if (argc != 2) {
132       Pmsg0(0, _("Wrong number of arguments: \n"));
133       usage();
134    }
135
136    working_directory = wd;
137
138    if (configfile == NULL) {
139       configfile = bstrdup(CONFIG_FILE);
140    }
141
142    parse_config(configfile);
143
144    /* Setup and acquire input device for reading */
145    in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName);
146    in_jcr->ignore_label_errors = ignore_label_errors;
147    in_dev = setup_to_access_device(in_jcr, 1);   /* read device */
148    if (!in_dev) { 
149       exit(1);
150    }
151
152    /* Setup output device for writing */
153    out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName);
154    out_dev = setup_to_access_device(out_jcr, 0);   /* no acquire */  
155    if (!out_dev) { 
156       exit(1);      
157    }
158    /* For we must now acquire the device for writing */
159    lock_device(out_dev);
160    if (open_dev(out_dev, out_jcr->VolumeName, OPEN_READ_WRITE) < 0) {
161       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
162       unlock_device(out_dev);
163       exit(1);
164    }
165    unlock_device(out_dev);
166    if (!acquire_device_for_append(out_jcr)) {
167       free_jcr(in_jcr);
168       exit(1);
169    }
170    out_block = out_jcr->dcr->block;
171
172    read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
173    if (!write_block_to_device(out_jcr->dcr, out_block)) {
174       Pmsg0(000, _("Write of last block failed.\n"));
175    }
176
177    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
178
179    free_jcr(in_jcr);
180    free_jcr(out_jcr);
181
182    term_dev(in_dev);
183    term_dev(out_dev);
184    return 0;
185 }
186   
187
188 /*
189  * read_records() calls back here for each record it gets
190  */
191 static bool record_cb(JCR *in_jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
192 {
193    if (list_records) {
194       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
195             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex, 
196             rec->Stream, rec->data_len);
197    }
198    /* 
199     * Check for Start or End of Session Record 
200     *
201     */
202    if (rec->FileIndex < 0) {
203
204       if (verbose > 1) {
205          dump_label_record(dev, rec, 1);
206       }
207       switch (rec->FileIndex) {
208       case PRE_LABEL:
209          Pmsg0(000, "Volume is prelabeled. This volume cannot be copied.\n");
210          return false;
211       case VOL_LABEL:
212          Pmsg0(000, "Volume label not copied.\n");
213          return true;
214       case SOS_LABEL:
215          jobs++;
216          break;
217       case EOS_LABEL:
218          while (!write_record_to_block(out_block, rec)) {
219             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
220                        rec->remainder);
221             if (!write_block_to_device(out_jcr->dcr, out_block)) {
222                Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
223                   dev_name(out_dev), strerror_dev(out_dev));
224                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
225                      strerror_dev(out_dev));
226             }
227          }
228          if (!write_block_to_device(out_jcr->dcr, out_block)) {
229             Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
230                dev_name(out_dev), strerror_dev(out_dev));
231             Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
232                   strerror_dev(out_dev));
233          }
234          break;
235       case EOM_LABEL:
236          Pmsg0(000, "EOM label not copied.\n");
237          return true;
238       case EOT_LABEL:              /* end of all tapes */
239          Pmsg0(000, "EOT label not copied.\n");
240          return true;
241       default:
242          break;
243       }
244    }
245
246    /*  Write record */
247    records++;
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, out_block)) {
252          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
253             dev_name(out_dev), strerror_dev(out_dev));
254          Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
255                strerror_dev(out_dev));
256          break;
257       }
258    }
259    return true;
260 }
261
262
263 /* Dummies to replace askdir.c */
264 bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing) { return 1;}
265 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
266 bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
267 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
268 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
269 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
270 bool    dir_send_job_status(JCR *jcr) {return 1;}
271
272
273 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
274 {
275    JCR *jcr = dcr->jcr;
276    DEVICE *dev = dcr->dev;
277    fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
278       jcr->VolumeName, dev_name(dev));
279    getchar();   
280    return true;
281 }