]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
kes Fix bug #942 where lots of emails where generated when the heartbeat
[bacula/bacula] / bacula / src / stored / bcopy.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *  Program to copy a Bacula from one volume to another.
31  *
32  *   Kern E. Sibbald, October 2002
33  *
34  *
35  *   Version $Id$
36  */
37
38 #include "bacula.h"
39 #include "stored.h"
40
41 /* Dummy functions */
42 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
43
44 /* Forward referenced functions */
45 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
46
47
48 /* Global variables */
49 static DEVICE *in_dev = NULL;
50 static DEVICE *out_dev = NULL;
51 static JCR *in_jcr;                    /* input jcr */
52 static JCR *out_jcr;                   /* output jcr */
53 static BSR *bsr = NULL;
54 static const char *wd = "/tmp";
55 static int list_records = 0;
56 static uint32_t records = 0;
57 static uint32_t jobs = 0;
58 static DEV_BLOCK *out_block;
59
60 #define CONFIG_FILE "bacula-sd.conf"
61 char *configfile = NULL;
62 STORES *me = NULL;                    /* our Global resource */
63 bool forge_on = false;                /* proceed inspite of I/O errors */
64 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
65 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
66
67
68 static void usage()
69 {
70    fprintf(stderr, _(
71 PROG_COPYRIGHT
72 "\nVersion: %s (%s)\n\n"
73 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
74 "       -b bootstrap      specify a bootstrap file\n"
75 "       -c <file>         specify configuration file\n"
76 "       -d <nn>           set debug level to <nn>\n"
77 "       -dt               print timestamp in debug output\n"
78 "       -i                specify input Volume names (separated by |)\n"
79 "       -o                specify output Volume names (separated by |)\n"
80 "       -p                proceed inspite of errors\n"
81 "       -v                verbose\n"
82 "       -w <dir>          specify working directory (default /tmp)\n"
83 "       -?                print this message\n\n"), 2002, VERSION, BDATE);
84    exit(1);
85 }
86
87 int main (int argc, char *argv[])
88 {
89    int ch;
90    char *iVolumeName = NULL;
91    char *oVolumeName = NULL;
92    bool ignore_label_errors = false;
93
94    setlocale(LC_ALL, "");
95    bindtextdomain("bacula", LOCALEDIR);
96    textdomain("bacula");
97    init_stack_dump();
98
99    my_name_is(argc, argv, "bcopy");
100    init_msg(NULL, NULL);
101
102    while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
103       switch (ch) {
104       case 'b':
105          bsr = parse_bsr(NULL, optarg);
106          break;
107
108       case 'c':                    /* specify config file */
109          if (configfile != NULL) {
110             free(configfile);
111          }
112          configfile = bstrdup(optarg);
113          break;
114
115       case 'd':                    /* debug level */
116          if (*optarg == 't') {
117             dbg_timestamp = true;
118          } else {
119             debug_level = atoi(optarg);
120             if (debug_level <= 0) {
121                debug_level = 1;
122             }
123          }
124          break;
125
126       case 'i':                    /* input Volume name */
127          iVolumeName = optarg;
128          break;
129
130       case 'o':                    /* output Volume name */
131          oVolumeName = optarg;
132          break;
133
134       case 'p':
135          ignore_label_errors = true;
136          forge_on = true;
137          break;
138
139       case 'v':
140          verbose++;
141          break;
142
143       case 'w':
144          wd = optarg;
145          break;
146
147       case '?':
148       default:
149          usage();
150
151       }
152    }
153    argc -= optind;
154    argv += optind;
155
156    if (argc != 2) {
157       Pmsg0(0, _("Wrong number of arguments: \n"));
158       usage();
159    }
160
161    OSDependentInit();
162
163    working_directory = wd;
164
165    if (configfile == NULL) {
166       configfile = bstrdup(CONFIG_FILE);
167    }
168
169    parse_config(configfile);
170
171    /* Setup and acquire input device for reading */
172    Dmsg0(100, "About to setup input jcr\n");
173    in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
174    if (!in_jcr) {
175       exit(1);
176    }
177    in_jcr->ignore_label_errors = ignore_label_errors;
178    in_dev = in_jcr->dcr->dev;
179    if (!in_dev) {
180       exit(1);
181    }
182
183    /* Setup output device for writing */
184    Dmsg0(100, "About to setup output jcr\n");
185    out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
186    if (!out_jcr) {
187       exit(1);
188    }
189    out_dev = out_jcr->dcr->dev;
190    if (!out_dev) {
191       exit(1);
192    }
193    Dmsg0(100, "About to acquire device for writing\n");
194    /* For we must now acquire the device for writing */
195    out_dev->r_dlock();
196    if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
197       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
198       out_dev->dunlock();
199       exit(1);
200    }
201    out_dev->dunlock();
202    if (!acquire_device_for_append(out_jcr->dcr)) {
203       free_jcr(in_jcr);
204       exit(1);
205    }
206    out_block = out_jcr->dcr->block;
207
208    read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
209    if (!write_block_to_device(out_jcr->dcr)) {
210       Pmsg0(000, _("Write of last block failed.\n"));
211    }
212
213    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
214
215    free_jcr(in_jcr);
216    free_jcr(out_jcr);
217
218    in_dev->term();
219    out_dev->term();
220    return 0;
221 }
222
223
224 /*
225  * read_records() calls back here for each record it gets
226  */
227 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
228 {
229    if (list_records) {
230       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
231             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
232             rec->Stream, rec->data_len);
233    }
234    /*
235     * Check for Start or End of Session Record
236     *
237     */
238    if (rec->FileIndex < 0) {
239
240       if (verbose > 1) {
241          dump_label_record(in_dcr->dev, rec, 1);
242       }
243       switch (rec->FileIndex) {
244       case PRE_LABEL:
245          Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
246          return false;
247       case VOL_LABEL:
248          Pmsg0(000, _("Volume label not copied.\n"));
249          return true;
250       case SOS_LABEL:
251          jobs++;
252          break;
253       case EOS_LABEL:
254          while (!write_record_to_block(out_block, rec)) {
255             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
256                        rec->remainder);
257             if (!write_block_to_device(out_jcr->dcr)) {
258                Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
259                   out_dev->print_name(), out_dev->bstrerror());
260                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
261                      out_dev->bstrerror());
262             }
263          }
264          if (!write_block_to_device(out_jcr->dcr)) {
265             Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
266                out_dev->print_name(), out_dev->bstrerror());
267             Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
268                   out_dev->bstrerror());
269          }
270          break;
271       case EOM_LABEL:
272          Pmsg0(000, _("EOM label not copied.\n"));
273          return true;
274       case EOT_LABEL:              /* end of all tapes */
275          Pmsg0(000, _("EOT label not copied.\n"));
276          return true;
277       default:
278          break;
279       }
280    }
281
282    /*  Write record */
283    records++;
284    while (!write_record_to_block(out_block, rec)) {
285       Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
286                  rec->remainder);
287       if (!write_block_to_device(out_jcr->dcr)) {
288          Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
289             out_dev->print_name(), out_dev->bstrerror());
290          Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
291                out_dev->bstrerror());
292          break;
293       }
294    }
295    return true;
296 }
297
298
299 /* Dummies to replace askdir.c */
300 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
301 bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
302 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
303 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
304 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
305 bool    dir_send_job_status(JCR *jcr) {return 1;}
306
307
308 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
309 {
310    DEVICE *dev = dcr->dev;
311    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
312       dcr->VolumeName, dev->print_name());
313    dev->close();
314    getchar();
315    return true;
316 }
317
318 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing)
319 {
320    Dmsg0(100, "Fake dir_get_volume_info\n");
321    bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
322    dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
323    Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);
324    return 1;
325 }