]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bls.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / stored / bls.c
1 /*
2  *
3  *  Dumb program to do an "ls" of a Bacula 1.0 mortal file.
4  *
5  *   Version $Id$
6  */
7 /*
8    Copyright (C) 2000-2006 Kern Sibbald
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License
12    version 2 as amended with additional clauses defined in the
13    file LICENSE in the main source directory.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
18    the file LICENSE for additional details.
19
20  */
21
22 #include "bacula.h"
23 #include "stored.h"
24 #include "findlib/find.h"
25
26 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
27 int win32_client = 1;
28 #else
29 int win32_client = 0;
30 #endif
31
32 /* Dummy functions */
33 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
34
35 static void do_blocks(char *infname);
36 static void do_jobs(char *infname);
37 static void do_ls(char *fname);
38 static void do_close(JCR *jcr);
39 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
40 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
41
42 static DEVICE *dev;
43 static DCR *dcr;
44 static bool dump_label = false;
45 static bool list_blocks = false;
46 static bool list_jobs = false;
47 static DEV_RECORD *rec;
48 static JCR *jcr;
49 static SESSION_LABEL sessrec;
50 static uint32_t num_files = 0;
51 static ATTR *attr;
52
53 #define CONFIG_FILE "bacula-sd.conf"
54 char *configfile = NULL;
55 STORES *me = NULL;                    /* our Global resource */
56 bool forge_on = false;
57 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
58 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
59
60
61 static FF_PKT *ff;
62
63 static BSR *bsr = NULL;
64
65 static void usage()
66 {
67    fprintf(stderr, _(
68 "Copyright (C) 2000-2005 Kern Sibbald.\n"
69 "\nVersion: %s (%s)\n\n"
70 "Usage: bls [options] <device-name>\n"
71 "       -b <file>       specify a bootstrap file\n"
72 "       -c <file>       specify a config file\n"
73 "       -d <level>      specify debug level\n"
74 "       -e <file>       exclude list\n"
75 "       -i <file>       include list\n"
76 "       -j              list jobs\n"
77 "       -k              list blocks\n"
78 "    (no j or k option) list saved files\n"
79 "       -L              dump label\n"
80 "       -p              proceed inspite of errors\n"
81 "       -v              be verbose\n"
82 "       -V              specify Volume names (separated by |)\n"
83 "       -?              print this message\n\n"), VERSION, BDATE);
84    exit(1);
85 }
86
87
88 int main (int argc, char *argv[])
89 {
90    int i, ch;
91    FILE *fd;
92    char line[1000];
93    char *VolumeName= NULL;
94    char *bsrName = NULL;
95    bool ignore_label_errors = false;
96
97    setlocale(LC_ALL, "");
98    bindtextdomain("bacula", LOCALEDIR);
99    textdomain("bacula");
100
101    working_directory = "/tmp";
102    my_name_is(argc, argv, "bls");
103    init_msg(NULL, NULL);              /* initialize message handler */
104
105    ff = init_find_files();
106
107    while ((ch = getopt(argc, argv, "b:c:d:e:i:jkLpvV:?")) != -1) {
108       switch (ch) {
109       case 'b':
110          bsrName = optarg;
111          break;
112
113       case 'c':                    /* specify config file */
114          if (configfile != NULL) {
115             free(configfile);
116          }
117          configfile = bstrdup(optarg);
118          break;
119
120       case 'd':                    /* debug level */
121          debug_level = atoi(optarg);
122          if (debug_level <= 0)
123             debug_level = 1;
124          break;
125
126       case 'e':                    /* exclude list */
127          if ((fd = fopen(optarg, "r")) == NULL) {
128             Pmsg2(0, _("Could not open exclude file: %s, ERR=%s\n"),
129                optarg, strerror(errno));
130             exit(1);
131          }
132          while (fgets(line, sizeof(line), fd) != NULL) {
133             strip_trailing_junk(line);
134             Dmsg1(100, "add_exclude %s\n", line);
135             add_fname_to_exclude_list(ff, line);
136          }
137          fclose(fd);
138          break;
139
140       case 'i':                    /* include list */
141          if ((fd = fopen(optarg, "r")) == NULL) {
142             Pmsg2(0, _("Could not open include file: %s, ERR=%s\n"),
143                optarg, strerror(errno));
144             exit(1);
145          }
146          while (fgets(line, sizeof(line), fd) != NULL) {
147             strip_trailing_junk(line);
148             Dmsg1(100, "add_include %s\n", line);
149             add_fname_to_include_list(ff, 0, line);
150          }
151          fclose(fd);
152          break;
153
154       case 'j':
155          list_jobs = true;
156          break;
157
158       case 'k':
159          list_blocks = true;
160          break;
161
162       case 'L':
163          dump_label = true;
164          break;
165
166       case 'p':
167          ignore_label_errors = true;
168          forge_on = true;
169          break;
170
171       case 'v':
172          verbose++;
173          break;
174
175       case 'V':                    /* Volume name */
176          VolumeName = optarg;
177          break;
178
179       case '?':
180       default:
181          usage();
182
183       } /* end switch */
184    } /* end while */
185    argc -= optind;
186    argv += optind;
187
188    if (!argc) {
189       Pmsg0(0, _("No archive name specified\n"));
190       usage();
191    }
192
193    if (configfile == NULL) {
194       configfile = bstrdup(CONFIG_FILE);
195    }
196
197    parse_config(configfile);
198
199    if (ff->included_files_list == NULL) {
200       add_fname_to_include_list(ff, 0, "/");
201    }
202
203    for (i=0; i < argc; i++) {
204       if (bsrName) {
205          bsr = parse_bsr(NULL, bsrName);
206       }
207       jcr = setup_jcr("bls", argv[i], bsr, VolumeName, 1); /* acquire for read */
208       if (!jcr) {
209          exit(1);
210       }
211       jcr->ignore_label_errors = ignore_label_errors;
212       dev = jcr->dcr->dev;
213       if (!dev) {
214          exit(1);
215       }
216       dcr = jcr->dcr;
217       rec = new_record();
218       attr = new_attr();
219       /*
220        * Assume that we have already read the volume label.
221        * If on second or subsequent volume, adjust buffer pointer
222        */
223       if (dev->VolHdr.PrevVolumeName[0] != 0) { /* second volume */
224          Pmsg1(0, _("\n"
225                     "Warning, this Volume is a continuation of Volume %s\n"),
226                 dev->VolHdr.PrevVolumeName);
227       }
228
229       if (list_blocks) {
230          do_blocks(argv[i]);
231       } else if (list_jobs) {
232          do_jobs(argv[i]);
233       } else {
234          do_ls(argv[i]);
235       }
236       do_close(jcr);
237    }
238    if (bsr) {
239       free_bsr(bsr);
240    }
241    term_include_exclude_files(ff);
242    term_find_files(ff);
243    return 0;
244 }
245
246
247 static void do_close(JCR *jcr)
248 {
249    release_device(jcr->dcr);
250    free_attr(attr);
251    free_record(rec);
252    free_jcr(jcr);
253    term_dev(dev);
254 }
255
256
257 /* List just block information */
258 static void do_blocks(char *infname)
259 {
260    char buf1[100], buf2[100];
261    DEV_BLOCK *block = dcr->block;
262    for ( ;; ) {
263       if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) {
264          Dmsg1(100, "!read_block(): ERR=%s\n", dev->strerror());
265          if (dev->at_eot()) {
266             if (!mount_next_read_volume(dcr)) {
267                Jmsg(jcr, M_INFO, 0, _("Got EOM at file %u on device %s, Volume \"%s\"\n"),
268                   dev->file, dev->print_name(), dcr->VolumeName);
269                break;
270             }
271             /* Read and discard Volume label */
272             DEV_RECORD *record;
273             record = new_record();
274             read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK);
275             read_record_from_block(block, record);
276             get_session_record(dev, record, &sessrec);
277             free_record(record);
278             Jmsg(jcr, M_INFO, 0, _("Mounted Volume \"%s\".\n"), dcr->VolumeName);
279          } else if (dev->at_eof()) {
280             Jmsg(jcr, M_INFO, 0, _("End of file %u on device %s, Volume \"%s\"\n"),
281                dev->file, dev->print_name(), dcr->VolumeName);
282             Dmsg0(20, "read_record got eof. try again\n");
283             continue;
284          } else if (dev->is_short_block()) {
285             Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
286             continue;
287          } else {
288             /* I/O error */
289             display_tape_error_status(jcr, dev);
290             break;
291          }
292       }
293       if (!match_bsr_block(bsr, block)) {
294          Dmsg5(100, "reject Blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n",
295             block->BlockNumber, block->block_len, block->BlockVer,
296             block->VolSessionId, block->VolSessionTime);
297          continue;
298       }
299       Dmsg5(100, "Blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n",
300         block->BlockNumber, block->block_len, block->BlockVer,
301         block->VolSessionId, block->VolSessionTime);
302       if (verbose == 1) {
303          read_record_from_block(block, rec);
304          Pmsg9(-1, _("File:blk=%u:%u blk_num=%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n"),
305               dev->file, dev->block_num,
306               block->BlockNumber, block->block_len,
307               FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, rec->VolSessionTime,
308               stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
309          rec->remainder = 0;
310       } else if (verbose > 1) {
311          dump_block(block, "");
312       } else {
313          printf(_("Block: %d size=%d\n"), block->BlockNumber, block->block_len);
314       }
315
316    }
317    return;
318 }
319
320 /*
321  * We are only looking for labels or in particular Job Session records
322  */
323 static bool jobs_cb(DCR *dcr, DEV_RECORD *rec)
324 {
325    if (rec->FileIndex < 0) {
326       dump_label_record(dcr->dev, rec, verbose);
327    }
328    rec->remainder = 0;
329    return true;
330 }
331
332 /* Do list job records */
333 static void do_jobs(char *infname)
334 {
335    read_records(dcr, jobs_cb, mount_next_read_volume);
336 }
337
338 /* Do an ls type listing of an archive */
339 static void do_ls(char *infname)
340 {
341    if (dump_label) {
342       dump_volume_label(dev);
343       return;
344    }
345    read_records(dcr, record_cb, mount_next_read_volume);
346    printf("%u files found.\n", num_files);
347 }
348
349 /*
350  * Called here for each record from read_records()
351  */
352 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
353 {
354    if (rec->FileIndex < 0) {
355       get_session_record(dev, rec, &sessrec);
356       return true;
357    }
358    /* File Attributes stream */
359    if (rec->Stream == STREAM_UNIX_ATTRIBUTES ||
360        rec->Stream == STREAM_UNIX_ATTRIBUTES_EX) {
361
362       if (!unpack_attributes_record(jcr, rec->Stream, rec->data, attr)) {
363          if (!forge_on) {
364             Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
365          }
366          num_files++;
367          return true;
368       }
369
370       if (attr->file_index != rec->FileIndex) {
371          Emsg2(forge_on?M_WARNING:M_ERROR_TERM, 0, _("Record header file index %ld not equal record index %ld\n"),
372                rec->FileIndex, attr->file_index);
373       }
374
375       attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
376       build_attr_output_fnames(jcr, attr);
377
378       if (file_is_included(ff, attr->fname) && !file_is_excluded(ff, attr->fname)) {
379          if (verbose) {
380             Pmsg5(-1, _("FileIndex=%d VolSessionId=%d VolSessionTime=%d Stream=%d DataLen=%d\n"),
381                   rec->FileIndex, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
382          }
383          print_ls_output(jcr, attr);
384          num_files++;
385       }
386    }
387    return true;
388 }
389
390
391 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
392 {
393    const char *rtype;
394    memset(sessrec, 0, sizeof(sessrec));
395    switch (rec->FileIndex) {
396    case PRE_LABEL:
397       rtype = _("Fresh Volume Label");
398       break;
399    case VOL_LABEL:
400       rtype = _("Volume Label");
401       unser_volume_label(dev, rec);
402       break;
403    case SOS_LABEL:
404       rtype = _("Begin Job Session");
405       unser_session_label(sessrec, rec);
406       break;
407    case EOS_LABEL:
408       rtype = _("End Job Session");
409       break;
410    case EOM_LABEL:
411       rtype = _("End of Medium");
412       break;
413    default:
414       rtype = _("Unknown");
415       break;
416    }
417    Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
418          rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
419    if (verbose) {
420       Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
421             rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
422    }
423 }
424
425
426 /* Dummies to replace askdir.c */
427 bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing) { return 1;}
428 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
429 bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
430 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
431 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
432 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
433 bool    dir_send_job_status(JCR *jcr) {return 1;}
434 int     generate_job_event(JCR *jcr, const char *event) { return 1; }
435        
436
437 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
438 {
439    DEVICE *dev = dcr->dev;
440    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
441       dcr->VolumeName, dev->print_name());
442    getchar();
443    return true;
444 }