]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bls.c
aa2bc563dc1395823d5b55979ddd89a0ffb1f4f2
[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, 2001, 2002 Kern Sibbald and John Walker
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 as
12    published by the Free Software Foundation; either version 2 of
13    the License, or (at your option) any later version.
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 GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public
21    License along with this program; if not, write to the Free
22    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23    MA 02111-1307, USA.
24
25  */
26
27 #include "bacula.h"
28 #include "stored.h"
29 #include "findlib/find.h"
30
31 static void do_blocks(char *infname);
32 static void do_jobs(char *infname);
33 static void do_ls(char *fname);
34 static void do_close(JCR *jcr);
35 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
36 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
37
38 static DEVICE *dev;
39 static int default_tape = FALSE;
40 static int dump_label = FALSE;
41 static int list_blocks = FALSE;
42 static int list_jobs = FALSE;
43 static int verbose = 0;
44 static DEV_RECORD *rec;
45 static DEV_BLOCK *block;
46 static JCR *jcr;
47 static SESSION_LABEL sessrec;
48 static uint32_t num_files = 0;
49 static long record_file_index;
50
51 extern char BaculaId[];
52
53 static FF_PKT ff;
54
55 static BSR *bsr = NULL;
56
57 static void usage()
58 {
59    fprintf(stderr,
60 "\nVersion: " VERSION " (" DATE ")\n\n"
61 "Usage: bls [-d debug_level] <physical-device-name>\n"
62 "       -b <file>       specify a bootstrap file\n"
63 "       -e <file>       exclude list\n"
64 "       -i <file>       include list\n"
65 "       -j              list jobs\n"
66 "       -k              list blocks\n"
67 "       -L              list tape label\n"
68 "    (none of above)    list saved files\n"
69 "       -t              use default tape device\n"
70 "       -v              be verbose\n"
71 "       -?              print this message\n\n");
72    exit(1);
73 }
74
75
76 int main (int argc, char *argv[])
77 {
78    int i, ch;
79    FILE *fd;
80    char line[1000];
81
82    my_name_is(argc, argv, "bls");
83    init_msg(NULL, NULL);              /* initialize message handler */
84
85    memset(&ff, 0, sizeof(ff));
86    init_include_exclude_files(&ff);
87
88    while ((ch = getopt(argc, argv, "b:d:e:i:jkLtv?")) != -1) {
89       switch (ch) {
90          case 'b':
91             bsr = parse_bsr(NULL, optarg);
92 //          dump_bsr(bsr);
93             break;
94
95          case 'd':                    /* debug level */
96             debug_level = atoi(optarg);
97             if (debug_level <= 0)
98                debug_level = 1; 
99             break;
100
101          case 'e':                    /* exclude list */
102             if ((fd = fopen(optarg, "r")) == NULL) {
103                Pmsg2(0, "Could not open exclude file: %s, ERR=%s\n",
104                   optarg, strerror(errno));
105                exit(1);
106             }
107             while (fgets(line, sizeof(line), fd) != NULL) {
108                strip_trailing_junk(line);
109                Dmsg1(100, "add_exclude %s\n", line);
110                add_fname_to_exclude_list(&ff, line);
111             }
112             fclose(fd);
113             break;
114
115          case 'i':                    /* include list */
116             if ((fd = fopen(optarg, "r")) == NULL) {
117                Pmsg2(0, "Could not open include file: %s, ERR=%s\n",
118                   optarg, strerror(errno));
119                exit(1);
120             }
121             while (fgets(line, sizeof(line), fd) != NULL) {
122                strip_trailing_junk(line);
123                Dmsg1(100, "add_include %s\n", line);
124                add_fname_to_include_list(&ff, 0, line);
125             }
126             fclose(fd);
127             break;
128
129          case 'j':
130             list_jobs = TRUE;
131             break;
132
133          case 'k':
134             list_blocks = TRUE;
135             break;
136
137          case 'L':
138             dump_label = TRUE;
139             break;
140
141          case 't':
142             default_tape = TRUE;
143             break;
144
145          case 'v':
146             verbose++;
147             break;
148
149          case '?':
150          default:
151             usage();
152
153       }  
154    }
155    argc -= optind;
156    argv += optind;
157
158    if (!argc && !default_tape) {
159       Pmsg0(0, "No archive name specified\n");
160       usage();
161    }
162
163    if (ff.included_files_list == NULL) {
164       add_fname_to_include_list(&ff, 0, "/");
165    }
166
167    /* Try default device */
168    if (default_tape) {
169       do_ls(DEFAULT_TAPE_DRIVE);
170       return 0;
171    }
172
173    for (i=0; i < argc; i++) {
174       jcr = setup_jcr("bls", argv[i], bsr);
175       dev = setup_to_read_device(jcr);
176       if (!dev) {
177          exit(1);
178       }
179       rec = new_record();
180       block = new_block(dev);
181       /*
182        * Assume that we have already read the volume label.
183        * If on second or subsequent volume, adjust buffer pointer 
184        */
185       if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
186          Pmsg1(0, "\n\
187 Warning, this Volume is a continuation of Volume %s\n",
188                 dev->VolHdr.PrevVolName);
189       }
190
191       if (list_blocks) {
192          do_blocks(argv[i]);
193       } else if (list_jobs) {
194          do_jobs(argv[i]);
195       } else {
196          do_ls(argv[i]);
197       }
198       do_close(jcr);
199    }
200    if (bsr) {
201       free_bsr(bsr);
202    }
203    return 0;
204 }
205
206
207 static void do_close(JCR *jcr)
208 {
209    release_device(jcr, dev);
210    term_dev(dev);
211    free_record(rec);
212    free_block(block);
213    free_jcr(jcr);
214 }
215
216
217 /* List just block information */
218 static void do_blocks(char *infname)
219 {
220
221    dump_volume_label(dev);
222
223    if (verbose) {
224       rec = new_record();
225    }
226    for ( ;; ) {
227       if (!read_block_from_device(dev, block)) {
228          Dmsg0(20, "!read_block()\n");
229          if (dev->state & ST_EOT) {
230             if (!mount_next_read_volume(jcr, dev, block)) {
231                printf("End of File on device\n");
232                break;
233             }
234             DEV_RECORD *record;
235             record = new_record();
236             read_block_from_device(dev, block);
237             read_record_from_block(block, record);
238             get_session_record(dev, record, &sessrec);
239             free_record(record);
240             printf("Volume %s mounted.\n", jcr->VolumeName);
241             continue;
242          }
243          if (dev->state & ST_EOF) {
244             Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
245             Dmsg0(20, "read_record got eof. try again\n");
246             continue;
247          }
248          if (dev->state & ST_SHORT) {
249             Emsg0(M_INFO, 0, dev->errmsg);
250             continue;
251          }
252          display_error_status(dev);
253          break;
254       }
255
256       if (verbose) {
257          read_record_from_block(block, rec);
258          Pmsg6(-1, "Block: %d blen=%d First rec FI=%s SessId=%d Strm=%s rlen=%d\n",
259               block->BlockNumber, block->block_len,
260               FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
261               stream_to_ascii(rec->Stream), rec->data_len);
262          rec->remainder = 0;
263       } else {
264          printf("Block: %d size=%d\n", block->BlockNumber, block->block_len);
265       }
266
267    }
268    return;
269 }
270
271 /*
272  * We are only looking for labels or in particula Job Session records
273  */
274 static void jobs_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
275 {
276    if (rec->FileIndex < 0) {
277       dump_label_record(dev, rec, verbose);
278    }
279    rec->remainder = 0;
280 }
281
282 /* Do list job records */
283 static void do_jobs(char *infname)
284 {
285    read_records(jcr, dev, jobs_cb, mount_next_read_volume);
286 }
287
288 /* Do an ls type listing of an archive */
289 static void do_ls(char *infname)
290 {
291    if (dump_label) {
292       dump_volume_label(dev);
293       return;
294    }
295
296    read_records(jcr, dev, record_cb, mount_next_read_volume);
297 }
298
299 /*
300  * Called here for each record from read_records()
301  */
302 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
303 {
304    char fname[2000];
305    struct stat statp;
306    int type;
307
308    if (rec->FileIndex < 0) {
309       get_session_record(dev, rec, &sessrec);
310       return;
311    }
312    /* File Attributes stream */
313    if (rec->Stream == STREAM_UNIX_ATTRIBUTES) {
314       char *ap, *fp;
315       sscanf(rec->data, "%ld %d", &record_file_index, &type);
316       if (record_file_index != rec->FileIndex) {
317          Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n",
318             rec->FileIndex, record_file_index);
319       }
320       ap = rec->data;
321
322       while (*ap++ != ' ')         /* skip record file index */
323          ;
324       while (*ap++ != ' ')         /* skip type */
325          ;
326       /* Save filename and position to attributes */
327       fp = fname;
328       while (*ap != 0) {
329          *fp++  = *ap++;
330       }
331       *fp = *ap++;                 /* terminate filename & point to attribs */
332
333       decode_stat(ap, &statp);
334       /* Skip to link name */  
335       while (*ap++ != 0)
336          ;
337       if (file_is_included(&ff, fname) && !file_is_excluded(&ff, fname)) {
338          print_ls_output(fname, ap, type, &statp);
339          num_files++;
340       }
341    }
342    if (verbose) {
343       printf("%u files found.\n", num_files);
344    }
345    return;
346 }
347
348
349 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
350 {
351    char *rtype;
352    memset(sessrec, 0, sizeof(sessrec));
353    switch (rec->FileIndex) {
354       case PRE_LABEL:
355          rtype = "Fresh Volume Label";   
356          break;
357       case VOL_LABEL:
358          rtype = "Volume Label";
359          unser_volume_label(dev, rec);
360          break;
361       case SOS_LABEL:
362          rtype = "Begin Session";
363          unser_session_label(sessrec, rec);
364          break;
365       case EOS_LABEL:
366          rtype = "End Session";
367          break;
368       case EOM_LABEL:
369          rtype = "End of Media";
370          break;
371       default:
372          rtype = "Unknown";
373          break;
374    }
375    Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
376          rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
377 }
378
379
380 /* Dummies to replace askdir.c */
381 int     dir_get_volume_info(JCR *jcr, int writing) { return 1;}
382 int     dir_find_next_appendable_volume(JCR *jcr) { return 1;}
383 int     dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
384 int     dir_create_jobmedia_record(JCR *jcr) { return 1; }
385 int     dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
386 int     dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
387 int     dir_send_job_status(JCR *jcr) {return 1;}
388
389
390 int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
391 {
392    fprintf(stderr, "Mount Volume %s on device %s and press return when ready: ",
393       jcr->VolumeName, dev_name(dev));
394    getchar();   
395    return 1;
396 }