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