]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
- Set reconnect flag in MySQL packet to 1 to ensure that connection
[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 /* Dummy functions */
34 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
35
36 /* Forward referenced functions */
37 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
38
39
40 /* Global variables */
41 static DEVICE *in_dev = NULL;
42 static DEVICE *out_dev = NULL;
43 static JCR *in_jcr;                    /* input jcr */
44 static JCR *out_jcr;                   /* output jcr */
45 static BSR *bsr = NULL;
46 static const char *wd = "/tmp";
47 static int list_records = 0;
48 static uint32_t records = 0;
49 static uint32_t jobs = 0;
50 static DEV_BLOCK *out_block;
51
52 #define CONFIG_FILE "bacula-sd.conf"
53 char *configfile = NULL;
54 STORES *me = NULL;                    /* our Global resource */
55 bool forge_on = false;                /* proceed inspite of I/O errors */
56 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
57 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
58
59
60 static void usage()
61 {
62    fprintf(stderr, _(
63 "Copyright (C) 2002-2005 Kern Sibbald.\n"
64 "\nVersion: " VERSION " (" BDATE ")\n\n"
65 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
66 "       -b bootstrap      specify a bootstrap file\n"
67 "       -c <file>         specify configuration file\n"
68 "       -d <nn>           set debug level to nn\n"
69 "       -i                specify input Volume names (separated by |)\n"
70 "       -o                specify output Volume names (separated by |)\n"
71 "       -p                proceed inspite of errors\n"
72 "       -v                verbose\n"
73 "       -w <dir>          specify working directory (default /tmp)\n"
74 "       -?                print this message\n\n"));
75    exit(1);
76 }
77
78 int main (int argc, char *argv[])
79 {
80    int ch;
81    char *iVolumeName = NULL;
82    char *oVolumeName = NULL;
83    bool ignore_label_errors = false;
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    working_directory = wd;
143
144    if (configfile == NULL) {
145       configfile = bstrdup(CONFIG_FILE);
146    }
147
148    parse_config(configfile);
149
150    /* Setup and acquire input device for reading */
151    in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
152    if (!in_jcr) {
153       exit(1);
154    }
155    in_jcr->ignore_label_errors = ignore_label_errors;
156    in_dev = in_jcr->dcr->dev;
157    if (!in_dev) {
158       exit(1);
159    }
160
161    /* Setup output device for writing */
162    out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
163    if (!out_jcr) {
164       exit(1);
165    }
166    out_dev = out_jcr->dcr->dev;
167    if (!out_dev) {
168       exit(1);
169    }
170    /* For we must now acquire the device for writing */
171    lock_device(out_dev);
172    if (open_dev(out_dev, out_jcr->dcr->VolumeName, OPEN_READ_WRITE) < 0) {
173       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
174       unlock_device(out_dev);
175       exit(1);
176    }
177    unlock_device(out_dev);
178    if (!acquire_device_for_append(out_jcr->dcr)) {
179       free_jcr(in_jcr);
180       exit(1);
181    }
182    out_block = out_jcr->dcr->block;
183
184    read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
185    if (!write_block_to_device(out_jcr->dcr)) {
186       Pmsg0(000, _("Write of last block failed.\n"));
187    }
188
189    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
190
191    free_jcr(in_jcr);
192    free_jcr(out_jcr);
193
194    term_dev(in_dev);
195    term_dev(out_dev);
196    return 0;
197 }
198
199
200 /*
201  * read_records() calls back here for each record it gets
202  */
203 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
204 {
205    if (list_records) {
206       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
207             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
208             rec->Stream, rec->data_len);
209    }
210    /*
211     * Check for Start or End of Session Record
212     *
213     */
214    if (rec->FileIndex < 0) {
215
216       if (verbose > 1) {
217          dump_label_record(in_dcr->dev, rec, 1);
218       }
219       switch (rec->FileIndex) {
220       case PRE_LABEL:
221          Pmsg0(000, "Volume is prelabeled. This volume cannot be copied.\n");
222          return false;
223       case VOL_LABEL:
224          Pmsg0(000, "Volume label not copied.\n");
225          return true;
226       case SOS_LABEL:
227          jobs++;
228          break;
229       case EOS_LABEL:
230          while (!write_record_to_block(out_block, rec)) {
231             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
232                        rec->remainder);
233             if (!write_block_to_device(out_jcr->dcr)) {
234                Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
235                   out_dev->print_name(), strerror_dev(out_dev));
236                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
237                      strerror_dev(out_dev));
238             }
239          }
240          if (!write_block_to_device(out_jcr->dcr)) {
241             Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
242                out_dev->print_name(), strerror_dev(out_dev));
243             Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
244                   strerror_dev(out_dev));
245          }
246          break;
247       case EOM_LABEL:
248          Pmsg0(000, "EOM label not copied.\n");
249          return true;
250       case EOT_LABEL:              /* end of all tapes */
251          Pmsg0(000, "EOT label not copied.\n");
252          return true;
253       default:
254          break;
255       }
256    }
257
258    /*  Write record */
259    records++;
260    while (!write_record_to_block(out_block, rec)) {
261       Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
262                  rec->remainder);
263       if (!write_block_to_device(out_jcr->dcr)) {
264          Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
265             out_dev->print_name(), strerror_dev(out_dev));
266          Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
267                strerror_dev(out_dev));
268          break;
269       }
270    }
271    return true;
272 }
273
274
275 /* Dummies to replace askdir.c */
276 bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing) { return 1;}
277 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
278 bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
279 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
280 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
281 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
282 bool    dir_send_job_status(JCR *jcr) {return 1;}
283
284
285 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
286 {
287    DEVICE *dev = dcr->dev;
288    fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
289       dcr->VolumeName, dev->print_name());
290    getchar();
291    return true;
292 }