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