]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
kes Update copyright date in program files, and for the most part
[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-2006 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-%s 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"), BYEAR, 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    OSDependentInit();
142
143    working_directory = wd;
144
145    if (configfile == NULL) {
146       configfile = bstrdup(CONFIG_FILE);
147    }
148
149    parse_config(configfile);
150
151    /* Setup and acquire input device for reading */
152    in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
153    if (!in_jcr) {
154       exit(1);
155    }
156    in_jcr->ignore_label_errors = ignore_label_errors;
157    in_dev = in_jcr->dcr->dev;
158    if (!in_dev) {
159       exit(1);
160    }
161
162    /* Setup output device for writing */
163    out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
164    if (!out_jcr) {
165       exit(1);
166    }
167    out_dev = out_jcr->dcr->dev;
168    if (!out_dev) {
169       exit(1);
170    }
171    /* For we must now acquire the device for writing */
172    lock_device(out_dev);
173    if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
174       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
175       unlock_device(out_dev);
176       exit(1);
177    }
178    unlock_device(out_dev);
179    if (!acquire_device_for_append(out_jcr->dcr)) {
180       free_jcr(in_jcr);
181       exit(1);
182    }
183    out_block = out_jcr->dcr->block;
184
185    read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
186    if (!write_block_to_device(out_jcr->dcr)) {
187       Pmsg0(000, _("Write of last block failed.\n"));
188    }
189
190    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
191
192    free_jcr(in_jcr);
193    free_jcr(out_jcr);
194
195    in_dev->term();
196    out_dev->term();
197    return 0;
198 }
199
200
201 /*
202  * read_records() calls back here for each record it gets
203  */
204 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
205 {
206    if (list_records) {
207       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
208             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
209             rec->Stream, rec->data_len);
210    }
211    /*
212     * Check for Start or End of Session Record
213     *
214     */
215    if (rec->FileIndex < 0) {
216
217       if (verbose > 1) {
218          dump_label_record(in_dcr->dev, rec, 1);
219       }
220       switch (rec->FileIndex) {
221       case PRE_LABEL:
222          Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
223          return false;
224       case VOL_LABEL:
225          Pmsg0(000, _("Volume label not copied.\n"));
226          return true;
227       case SOS_LABEL:
228          jobs++;
229          break;
230       case EOS_LABEL:
231          while (!write_record_to_block(out_block, rec)) {
232             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
233                        rec->remainder);
234             if (!write_block_to_device(out_jcr->dcr)) {
235                Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
236                   out_dev->print_name(), out_dev->bstrerror());
237                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
238                      out_dev->bstrerror());
239             }
240          }
241          if (!write_block_to_device(out_jcr->dcr)) {
242             Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
243                out_dev->print_name(), out_dev->bstrerror());
244             Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
245                   out_dev->bstrerror());
246          }
247          break;
248       case EOM_LABEL:
249          Pmsg0(000, _("EOM label not copied.\n"));
250          return true;
251       case EOT_LABEL:              /* end of all tapes */
252          Pmsg0(000, _("EOT label not copied.\n"));
253          return true;
254       default:
255          break;
256       }
257    }
258
259    /*  Write record */
260    records++;
261    while (!write_record_to_block(out_block, rec)) {
262       Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
263                  rec->remainder);
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          break;
270       }
271    }
272    return true;
273 }
274
275
276 /* Dummies to replace askdir.c */
277 bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing) { return 1;}
278 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
279 bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
280 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
281 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
282 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
283 bool    dir_send_job_status(JCR *jcr) {return 1;}
284
285
286 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
287 {
288    DEVICE *dev = dcr->dev;
289    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
290       dcr->VolumeName, dev->print_name());
291    getchar();
292    return true;
293 }