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