]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bls.c
More SD tools cleanup
[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             break;
93
94          case 'd':                    /* debug level */
95             debug_level = atoi(optarg);
96             if (debug_level <= 0)
97                debug_level = 1; 
98             break;
99
100          case 'e':                    /* exclude list */
101             if ((fd = fopen(optarg, "r")) == NULL) {
102                Pmsg2(0, "Could not open exclude file: %s, ERR=%s\n",
103                   optarg, strerror(errno));
104                exit(1);
105             }
106             while (fgets(line, sizeof(line), fd) != NULL) {
107                strip_trailing_junk(line);
108                Dmsg1(100, "add_exclude %s\n", line);
109                add_fname_to_exclude_list(&ff, line);
110             }
111             fclose(fd);
112             break;
113
114          case 'i':                    /* include list */
115             if ((fd = fopen(optarg, "r")) == NULL) {
116                Pmsg2(0, "Could not open include file: %s, ERR=%s\n",
117                   optarg, strerror(errno));
118                exit(1);
119             }
120             while (fgets(line, sizeof(line), fd) != NULL) {
121                strip_trailing_junk(line);
122                Dmsg1(100, "add_include %s\n", line);
123                add_fname_to_include_list(&ff, 0, line);
124             }
125             fclose(fd);
126             break;
127
128          case 'j':
129             list_jobs = TRUE;
130             break;
131
132          case 'k':
133             list_blocks = TRUE;
134             break;
135
136          case 'L':
137             dump_label = TRUE;
138             break;
139
140          case 't':
141             default_tape = TRUE;
142             break;
143
144          case 'v':
145             verbose++;
146             break;
147
148          case '?':
149          default:
150             usage();
151
152       }  
153    }
154    argc -= optind;
155    argv += optind;
156
157    if (!argc && !default_tape) {
158       Pmsg0(0, "No archive name specified\n");
159       usage();
160    }
161
162    if (ff.included_files_list == NULL) {
163       add_fname_to_include_list(&ff, 0, "/");
164    }
165
166    /* Try default device */
167    if (default_tape) {
168       do_ls(DEFAULT_TAPE_DRIVE);
169       return 0;
170    }
171
172    for (i=0; i < argc; i++) {
173       jcr = setup_jcr("bls", argv[i], bsr);
174       dev = setup_to_read_device(jcr);
175       if (!dev) {
176          exit(1);
177       }
178       rec = new_record();
179       block = new_block(dev);
180       /*
181        * Assume that we have already read the volume label.
182        * If on second or subsequent volume, adjust buffer pointer 
183        */
184       if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
185          Pmsg1(0, "\n\
186 Warning, this Volume is a continuation of Volume %s\n",
187                 dev->VolHdr.PrevVolName);
188       }
189
190       if (list_blocks) {
191          do_blocks(argv[i]);
192       } else if (list_jobs) {
193          do_jobs(argv[i]);
194       } else {
195          do_ls(argv[i]);
196       }
197       do_close(jcr);
198    }
199    if (bsr) {
200       free_bsr(bsr);
201    }
202    return 0;
203 }
204
205
206 static void do_close(JCR *jcr)
207 {
208    release_device(jcr, dev);
209    term_dev(dev);
210    free_record(rec);
211    free_block(block);
212    free_jcr(jcr);
213 }
214
215
216 /* List just block information */
217 static void do_blocks(char *infname)
218 {
219
220    dump_volume_label(dev);
221
222    if (verbose) {
223       rec = new_record();
224    }
225    for ( ;; ) {
226       if (!read_block_from_device(dev, block)) {
227          Dmsg0(20, "!read_block()\n");
228          if (dev->state & ST_EOT) {
229             if (!mount_next_read_volume(jcr, dev, block)) {
230                printf("End of File on device\n");
231                break;
232             }
233             DEV_RECORD *record;
234             record = new_record();
235             read_block_from_device(dev, block);
236             read_record_from_block(block, record);
237             get_session_record(dev, record, &sessrec);
238             free_record(record);
239             printf("Volume %s mounted.\n", jcr->VolumeName);
240             continue;
241          }
242          if (dev->state & ST_EOF) {
243             Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
244             Dmsg0(20, "read_record got eof. try again\n");
245             continue;
246          }
247          if (dev->state & ST_SHORT) {
248             Emsg0(M_INFO, 0, dev->errmsg);
249             continue;
250          }
251          display_error_status(dev);
252          break;
253       }
254
255       if (verbose) {
256          read_record_from_block(block, rec);
257          Pmsg6(-1, "Block: %d blen=%d First rec FI=%s SessId=%d Strm=%s rlen=%d\n",
258               block->BlockNumber, block->block_len,
259               FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
260               stream_to_ascii(rec->Stream), rec->data_len);
261          rec->remainder = 0;
262       } else {
263          printf("Block: %d size=%d\n", block->BlockNumber, block->block_len);
264       }
265
266    }
267    return;
268 }
269
270 /*
271  * We are only looking for labels or in particula Job Session records
272  */
273 static void jobs_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
274 {
275    if (rec->FileIndex < 0) {
276       dump_label_record(dev, rec, verbose);
277    }
278    rec->remainder = 0;
279 }
280
281 /* Do list job records */
282 static void do_jobs(char *infname)
283 {
284    read_records(jcr, dev, jobs_cb, mount_next_read_volume);
285 }
286
287 /* Do an ls type listing of an archive */
288 static void do_ls(char *infname)
289 {
290    if (dump_label) {
291       dump_volume_label(dev);
292       return;
293    }
294
295    read_records(jcr, dev, record_cb, mount_next_read_volume);
296 }
297
298 /*
299  * Called here for each record from read_records()
300  */
301 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
302 {
303    char fname[2000];
304    struct stat statp;
305    int type;
306
307    if (rec->FileIndex < 0) {
308       get_session_record(dev, rec, &sessrec);
309       return;
310    }
311    /* File Attributes stream */
312    if (rec->Stream == STREAM_UNIX_ATTRIBUTES) {
313       char *ap, *fp;
314       sscanf(rec->data, "%ld %d", &record_file_index, &type);
315       if (record_file_index != rec->FileIndex) {
316          Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n",
317             rec->FileIndex, record_file_index);
318       }
319       ap = rec->data;
320
321       while (*ap++ != ' ')         /* skip record file index */
322          ;
323       while (*ap++ != ' ')         /* skip type */
324          ;
325       /* Save filename and position to attributes */
326       fp = fname;
327       while (*ap != 0) {
328          *fp++  = *ap++;
329       }
330       *fp = *ap++;                 /* terminate filename & point to attribs */
331
332       decode_stat(ap, &statp);
333       /* Skip to link name */  
334       while (*ap++ != 0)
335          ;
336       if (file_is_included(&ff, fname) && !file_is_excluded(&ff, fname)) {
337          print_ls_output(fname, ap, type, &statp);
338          num_files++;
339       }
340    }
341    if (verbose) {
342       printf("%u files found.\n", num_files);
343    }
344    return;
345 }
346
347
348 static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
349 {
350    char *rtype;
351    memset(sessrec, 0, sizeof(sessrec));
352    switch (rec->FileIndex) {
353       case PRE_LABEL:
354          rtype = "Fresh Volume Label";   
355          break;
356       case VOL_LABEL:
357          rtype = "Volume Label";
358          unser_volume_label(dev, rec);
359          break;
360       case SOS_LABEL:
361          rtype = "Begin Session";
362          unser_session_label(sessrec, rec);
363          break;
364       case EOS_LABEL:
365          rtype = "End Session";
366          break;
367       case EOM_LABEL:
368          rtype = "End of Media";
369          break;
370       default:
371          rtype = "Unknown";
372          break;
373    }
374    Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
375          rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
376 }
377
378
379 /* Dummies to replace askdir.c */
380 int     dir_get_volume_info(JCR *jcr) { return 1;}
381 int     dir_find_next_appendable_volume(JCR *jcr) { return 1;}
382 int     dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
383 int     dir_create_jobmedia_record(JCR *jcr) { return 1; }
384 int     dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
385 int     dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
386 int     dir_send_job_status(JCR *jcr) {return 1;}
387
388
389 int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
390 {
391    fprintf(stderr, "Mount Volume %s on device %s and press return when ready: ",
392       jcr->VolumeName, dev_name(dev));
393    getchar();   
394    return 1;
395 }