]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bcopy.c
Backport new lock calls + debug for SD
[bacula/bacula] / bacula / src / stored / bcopy.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2012 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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
36 #include "bacula.h"
37 #include "stored.h"
38
39 /* Dummy functions */
40 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
41 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
42
43 /* Forward referenced functions */
44 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
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 bool list_records = false;
56 static uint32_t records = 0;
57 static uint32_t jobs = 0;
58 static DEV_BLOCK *out_block;
59 static SESSION_LABEL sessrec;
60
61 static CONFIG *config;
62 #define CONFIG_FILE "bacula-sd.conf"
63 char *configfile = NULL;
64 STORES *me = NULL;                    /* our Global resource */
65 bool forge_on = false;                /* proceed inspite of I/O errors */
66 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
67 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
68
69
70 static void usage()
71 {
72    fprintf(stderr, _(
73 PROG_COPYRIGHT
74 "\nVersion: %s (%s)\n\n"
75 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
76 "       -b bootstrap      specify a bootstrap file\n"
77 "       -c <file>         specify a Storage configuration file\n"
78 "       -d <nn>           set debug level to <nn>\n"
79 "       -dt               print timestamp in debug output\n"
80 "       -i                specify input Volume names (separated by |)\n"
81 "       -o                specify output Volume names (separated by |)\n"
82 "       -p                proceed inspite of errors\n"
83 "       -v                verbose\n"
84 "       -w <dir>          specify working directory (default /tmp)\n"
85 "       -?                print this message\n\n"), 2002, VERSION, BDATE);
86    exit(1);
87 }
88
89 int main (int argc, char *argv[])
90 {
91    int ch;
92    char *iVolumeName = NULL;
93    char *oVolumeName = NULL;
94    bool ignore_label_errors = false;
95    bool ok;
96
97    setlocale(LC_ALL, "");
98    bindtextdomain("bacula", LOCALEDIR);
99    textdomain("bacula");
100    init_stack_dump();
101
102    my_name_is(argc, argv, "bcopy");
103    lmgr_init_thread();
104    init_msg(NULL, NULL);
105
106    while ((ch = getopt(argc, argv, "b:c:d:i:o:pvw:?")) != -1) {
107       switch (ch) {
108       case 'b':
109          bsr = parse_bsr(NULL, optarg);
110          break;
111
112       case 'c':                    /* specify config file */
113          if (configfile != NULL) {
114             free(configfile);
115          }
116          configfile = bstrdup(optarg);
117          break;
118
119       case 'd':                    /* debug level */
120          if (*optarg == 't') {
121             dbg_timestamp = true;
122          } else {
123             debug_level = atoi(optarg);
124             if (debug_level <= 0) {
125                debug_level = 1;
126             }
127          }
128          break;
129
130       case 'i':                    /* input Volume name */
131          iVolumeName = optarg;
132          break;
133
134       case 'o':                    /* output Volume name */
135          oVolumeName = optarg;
136          break;
137
138       case 'p':
139          ignore_label_errors = true;
140          forge_on = true;
141          break;
142
143       case 'v':
144          verbose++;
145          break;
146
147       case 'w':
148          wd = optarg;
149          break;
150
151       case '?':
152       default:
153          usage();
154
155       }
156    }
157    argc -= optind;
158    argv += optind;
159
160    if (argc != 2) {
161       Pmsg0(0, _("Wrong number of arguments: \n"));
162       usage();
163    }
164
165    OSDependentInit();
166
167    working_directory = wd;
168
169    if (configfile == NULL) {
170       configfile = bstrdup(CONFIG_FILE);
171    }
172
173    config = new_config_parser();
174    parse_sd_config(config, configfile, M_ERROR_TERM);
175
176    /* Setup and acquire input device for reading */
177    Dmsg0(100, "About to setup input jcr\n");
178    in_jcr = setup_jcr("bcopy", argv[0], bsr, iVolumeName, 1); /* read device */
179    if (!in_jcr) {
180       exit(1);
181    }
182    in_jcr->ignore_label_errors = ignore_label_errors;
183    in_dev = in_jcr->dcr->dev;
184    if (!in_dev) {
185       exit(1);
186    }
187
188    /* Setup output device for writing */
189    Dmsg0(100, "About to setup output jcr\n");
190    out_jcr = setup_jcr("bcopy", argv[1], bsr, oVolumeName, 0); /* no acquire */
191    if (!out_jcr) {
192       exit(1);
193    }
194    out_dev = out_jcr->dcr->dev;
195    if (!out_dev) {
196       exit(1);
197    }
198    Dmsg0(100, "About to acquire device for writing\n");
199    /* For we must now acquire the device for writing */
200    out_dev->rLock(false);
201    if (!out_dev->open(out_jcr->dcr, OPEN_READ_WRITE)) {
202       Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
203       out_dev->Unlock();
204       exit(1);
205    }
206    out_dev->Unlock();
207    if (!acquire_device_for_append(out_jcr->dcr)) {
208       free_jcr(in_jcr);
209       exit(1);
210    }
211    out_block = out_jcr->dcr->block;
212
213    ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
214
215    if (ok || out_dev->can_write()) {
216       if (!out_jcr->dcr->write_block_to_device()) {
217          Pmsg0(000, _("Write of last block failed.\n"));
218       }
219    }
220
221    Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
222
223    free_jcr(in_jcr);
224    free_jcr(out_jcr);
225
226    in_dev->term();
227    out_dev->term();
228    return 0;
229 }
230
231
232 /*
233  * read_records() calls back here for each record it gets
234  */
235 static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
236 {
237    if (list_records) {
238       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
239             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
240             rec->Stream, rec->data_len);
241    }
242    /*
243     * Check for Start or End of Session Record
244     *
245     */
246    if (rec->FileIndex < 0) {
247       get_session_record(in_dcr->dev, rec, &sessrec);
248
249       if (verbose > 1) {
250          dump_label_record(in_dcr->dev, rec, 1);
251       }
252       switch (rec->FileIndex) {
253       case PRE_LABEL:
254          Pmsg0(000, _("Volume is prelabeled. This volume cannot be copied.\n"));
255          return false;
256       case VOL_LABEL:
257          Pmsg0(000, _("Volume label not copied.\n"));
258          return true;
259       case SOS_LABEL:
260          if (bsr && rec->match_stat < 1) {
261             /* Skipping record, because does not match BSR filter */
262             if (verbose) {
263              Pmsg0(-1, _("Copy skipped. Record does not match BSR filter.\n"));
264             }
265          } else {
266             jobs++;
267          }
268          break;
269       case EOS_LABEL:
270          if (bsr && rec->match_stat < 1) {
271             /* Skipping record, because does not match BSR filter */
272            return true;
273         }
274          while (!write_record_to_block(out_jcr->dcr, rec)) {
275             Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
276                        rec->remainder);
277             if (!out_jcr->dcr->write_block_to_device()) {
278                Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
279                   out_dev->print_name(), out_dev->bstrerror());
280                Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
281                      out_dev->bstrerror());
282                return false;
283             }
284          }
285          if (!out_jcr->dcr->write_block_to_device()) {
286             Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
287                out_dev->print_name(), out_dev->bstrerror());
288             Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
289                   out_dev->bstrerror());
290             return false;
291          }
292          return true;
293       case EOM_LABEL:
294          Pmsg0(000, _("EOM label not copied.\n"));
295          return true;
296       case EOT_LABEL:              /* end of all tapes */
297          Pmsg0(000, _("EOT label not copied.\n"));
298          return true;
299       default:
300          return true;
301       }
302    }
303
304    /*  Write record */
305    if (bsr && rec->match_stat < 1) {
306       /* Skipping record, because does not match BSR filter */
307       return true;
308    }
309    records++;
310    while (!write_record_to_block(out_jcr->dcr, rec)) {
311       Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
312                  rec->remainder);
313       if (!out_jcr->dcr->write_block_to_device()) {
314          Dmsg2(90, "Got write_block_to_dev error on device %s: ERR=%s\n",
315             out_dev->print_name(), out_dev->bstrerror());
316          Jmsg(out_jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
317                out_dev->bstrerror());
318          return false;
319       }
320    }
321    return true;
322 }
323
324 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
325 {
326    const char *rtype;
327    memset(sessrec, 0, sizeof(SESSION_LABEL));
328    switch (rec->FileIndex) {
329    case PRE_LABEL:
330       rtype = _("Fresh Volume Label");
331       break;
332    case VOL_LABEL:
333       rtype = _("Volume Label");
334       unser_volume_label(dev, rec);
335       break;
336    case SOS_LABEL:
337       rtype = _("Begin Job Session");
338       unser_session_label(sessrec, rec);
339       break;
340    case EOS_LABEL:
341       rtype = _("End Job Session");
342       unser_session_label(sessrec, rec);
343       break;
344    case 0:
345    case EOM_LABEL:
346       rtype = _("End of Medium");
347       break;
348    default:
349       rtype = _("Unknown");
350       break;
351    }
352    Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
353          rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
354    if (verbose) {
355       Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
356             rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
357    }
358 }
359
360
361 /* Dummies to replace askdir.c */
362 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
363 bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
364 bool    dir_create_jobmedia_record(DCR *dcr, bool zero) { return 1; }
365 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
366 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
367 bool    dir_send_job_status(JCR *jcr) {return 1;}
368
369
370 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
371 {
372    DEVICE *dev = dcr->dev;
373    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
374       dcr->VolumeName, dev->print_name());
375    dev->close();
376    getchar();
377    return true;
378 }
379
380 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing)
381 {
382    Dmsg0(100, "Fake dir_get_volume_info\n");
383    dcr->setVolCatName(dcr->VolumeName);
384    dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
385    Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatParts);
386    return 1;
387 }