]> 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  */
6 /*
7    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2 of
12    the License, or (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public
20    License along with this program; if not, write to the Free
21    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22    MA 02111-1307, USA.
23
24  */
25
26 #include "bacula.h"
27 #include "stored.h"
28 #include "findlib/find.h"
29
30 static void do_blocks(char *infname);
31 static void do_jobs(char *infname);
32 static void do_ls(char *fname);
33 static void print_ls_output(char *fname, char *link, int type, struct stat *statp);
34
35 static DEVICE *dev;
36 static int default_tape = FALSE;
37 static int dump_label = FALSE;
38 static int list_blocks = FALSE;
39 static int list_jobs = FALSE;
40 static int verbose = 0;
41
42 extern char BaculaId[];
43
44 static FF_PKT ff;
45
46 static void usage()
47 {
48    fprintf(stderr,
49 "Usage: bls [-d debug_level] <physical-device-name>\n"
50 "       -b              list blocks\n"
51 "       -e <file>       exclude list\n"
52 "       -i <file>       include list\n"
53 "       -j              list jobs\n"
54 "       -L              list tape label\n"
55 "    (none of above)    list saved files\n"
56 "       -t              use default tape device\n"
57 "       -v              be verbose\n"
58 "       -?              print this message\n\n");
59    exit(1);
60 }
61
62
63 int main (int argc, char *argv[])
64 {
65    int i, ch;
66    FILE *fd;
67    char line[1000];
68
69    my_name_is(argc, argv, "bls");
70
71    memset(&ff, 0, sizeof(ff));
72    init_include_exclude_files(&ff);
73
74    while ((ch = getopt(argc, argv, "bd:e:i:jLtv?")) != -1) {
75       switch (ch) {
76          case 'b':
77             list_blocks = TRUE;
78             break;
79          case 'd':                    /* debug level */
80             debug_level = atoi(optarg);
81             if (debug_level <= 0)
82                debug_level = 1; 
83             break;
84
85          case 'e':                    /* exclude list */
86             if ((fd = fopen(optarg, "r")) == NULL) {
87                Dmsg2(0, "Could not open exclude file: %s, ERR=%s\n",
88                   optarg, strerror(errno));
89                exit(1);
90             }
91             while (fgets(line, sizeof(line), fd) != NULL) {
92                strip_trailing_junk(line);
93                Dmsg1(000, "add_exclude %s\n", line);
94                add_fname_to_exclude_list(&ff, line);
95             }
96             fclose(fd);
97             break;
98
99          case 'i':                    /* include list */
100             if ((fd = fopen(optarg, "r")) == NULL) {
101                Dmsg2(0, "Could not open include file: %s, ERR=%s\n",
102                   optarg, strerror(errno));
103                exit(1);
104             }
105             while (fgets(line, sizeof(line), fd) != NULL) {
106                strip_trailing_junk(line);
107                Dmsg1(000, "add_include %s\n", line);
108                add_fname_to_include_list(&ff, 0, line);
109             }
110             fclose(fd);
111             break;
112
113          case 'j':
114             list_jobs = TRUE;
115             break;
116
117          case 'L':
118             dump_label = TRUE;
119             break;
120
121          case 't':
122             default_tape = TRUE;
123             break;
124
125          case 'v':
126             verbose++;
127             break;
128
129          case '?':
130          default:
131             usage();
132
133       }  
134    }
135    argc -= optind;
136    argv += optind;
137
138    if (!argc && !default_tape) {
139       Dmsg0(0, "No archive name specified\n");
140       usage();
141    }
142
143    if (ff.included_files_list == NULL) {
144       add_fname_to_include_list(&ff, 0, "/");
145    }
146
147    /*
148     * Ensure that every message is always printed
149     */
150    for (i=1; i<=M_MAX; i++) {
151       add_msg_dest(NULL, MD_STDOUT, i, NULL, NULL);
152    }
153
154    /* Try default device */
155    if (default_tape) {
156       do_ls(DEFAULT_TAPE_DRIVE);
157       return 0;
158    }
159
160
161    for (i=0; i < argc; i++) {
162       if (list_blocks) {
163          do_blocks(argv[i]);
164       } else if (list_jobs) {
165          do_jobs(argv[i]);
166       } else {
167          do_ls(argv[i]);
168       }
169    }
170
171    return 0;
172 }
173
174 static void my_free_jcr(JCR *jcr)
175 {
176    return;
177 }
178
179 /* List just block information */
180 static void do_blocks(char *infname)
181 {
182    char Vol[2000];
183    char *VolName;
184    char *p;
185    DEV_RECORD *rec;
186    DEV_BLOCK *block;
187    int NumVolumes, CurVolume;
188    JCR *jcr;
189
190    jcr = new_jcr(sizeof(JCR), my_free_jcr);
191    VolName = Vol;
192    VolName[0] = 0;
193    if (strncmp(infname, "/dev/", 5) != 0) {
194       /* Try stripping file part */
195       p = infname + strlen(infname);
196       while (p >= infname && *p != '/')
197          p--;
198       if (*p == '/') {
199          strcpy(VolName, p+1);
200          *p = 0;
201       }
202    }
203    Dmsg2(10, "Device=%s, Vol=%s.\n", infname, VolName);
204    dev = init_dev(NULL, infname);
205    if (!dev) {
206       Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
207    }
208    /* ***FIXME**** init capabilities */
209    if (!open_device(dev)) {
210       Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
211    }
212    Dmsg0(90, "Device opened for read.\n");
213
214    rec = new_record();
215    block = new_block(dev);
216
217    NumVolumes = 0;
218    CurVolume = 1;
219    for (p = VolName; p && *p; ) {
220       p = strchr(p, '^');
221       if (p) {
222          *p++ = 0;
223       }
224       NumVolumes++;
225    }
226
227    jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, strlen(VolName)+1);
228    strcpy(jcr->VolumeName, VolName);
229    if (!acquire_device_for_read(jcr, dev, block)) {
230       Emsg0(M_ERROR, 0, dev->errmsg);
231       exit(1);
232    }
233
234    dump_volume_label(dev);
235
236    /* Assume that we have already read the volume label.
237     * If on second or subsequent volume, adjust buffer pointer 
238     */
239    if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
240       Dmsg1(0, "\n\
241 Warning, this Volume is a continuation of Volume %s\n",
242                 dev->VolHdr.PrevVolName);
243    }
244  
245    for ( ;; ) {
246
247       if (!read_block_from_device(dev, block)) {
248          uint32_t status;
249          Dmsg0(20, "!read_record()\n");
250          if (dev->state & ST_EOT) {
251             if (rec->remainder) {
252                Dmsg0(20, "Not end of record.\n");
253             }
254             Dmsg2(20, "NumVolumes=%d CurVolume=%d\n", NumVolumes, CurVolume);
255             if (NumVolumes > 1 && CurVolume < NumVolumes) {
256                p = VolName;
257                while (*p++)  
258                   { }
259                CurVolume++;
260                Dmsg1(20, "There is another volume %s.\n", p);
261                VolName = p;
262                close_dev(dev);
263                jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, 
264                                    strlen(VolName)+1);
265                strcpy(jcr->VolumeName, VolName);
266                printf("Mount Volume %s on device %s and press return when ready.",
267                   VolName, infname);
268                getchar();   
269                block->binbuf = 0;     /* consumed all bytes */
270                if (!ready_dev_for_read(jcr, dev, block)) {
271                   Emsg2(M_ABORT, 0, "Cannot open Dev=%s, Vol=%s\n", infname, VolName);
272                }
273                continue;
274             }
275             printf("End of Device reached.\n");
276             break;
277          }
278          if (dev->state & ST_EOF) {
279             Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
280             Dmsg0(20, "read_record got eof. try again\n");
281             continue;
282          }
283          if (dev->state & ST_SHORT) {
284             Emsg0(M_INFO, 0, dev->errmsg);
285             continue;
286          }
287          Emsg0(M_ERROR, 0, dev->errmsg);
288          status_dev(dev, &status);
289          Dmsg1(20, "Device status: %x\n", status);
290          if (status & MT_EOD)
291             Emsg0(M_ABORT, 0, "Unexpected End of Data\n");
292          else if (status & MT_EOT)
293             Emsg0(M_ABORT, 0, "Unexpected End of Tape\n");
294          else if (status & MT_EOF)
295             Emsg0(M_ABORT, 0, "Unexpected End of File\n");
296          else if (status & MT_DR_OPEN)
297             Emsg0(M_ABORT, 0, "Tape Door is Open\n");
298          else if (!(status & MT_ONLINE))
299             Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n");
300          else
301             Emsg2(M_ABORT, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno));
302          break;
303       }
304
305       printf("Block: %d size=%d\n", block->BlockNumber, block->block_len);
306
307    }
308    term_dev(dev);
309    free_record(rec);
310    free_block(block);
311    free_jcr(jcr);
312    return;
313 }
314
315 /* Do list job records */
316 static void do_jobs(char *infname)
317 {
318    char Vol[2000];
319    char *VolName;
320    char *p;
321    DEV_RECORD *rec;
322    DEV_BLOCK *block;
323    int NumVolumes, CurVolume;
324    JCR *jcr;
325
326    jcr = new_jcr(sizeof(JCR), my_free_jcr);
327    VolName = Vol;
328    VolName[0] = 0;
329    if (strncmp(infname, "/dev/", 5) != 0) {
330       /* Try stripping file part */
331       p = infname + strlen(infname);
332       while (p >= infname && *p != '/')
333          p--;
334       if (*p == '/') {
335          strcpy(VolName, p+1);
336          *p = 0;
337       }
338    }
339    Dmsg2(10, "Device=%s, Vol=%s.\n", infname, VolName);
340    dev = init_dev(NULL, infname);
341    if (!dev) {
342       Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
343    }
344    /* ***FIXME**** init capabilities */
345    if (!open_device(dev)) {
346       Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
347    }
348    Dmsg0(90, "Device opened for read.\n");
349
350    rec = new_record();
351    block = new_block(dev);
352
353    NumVolumes = 0;
354    CurVolume = 1;
355    for (p = VolName; p && *p; ) {
356       p = strchr(p, '^');
357       if (p) {
358          *p++ = 0;
359       }
360       NumVolumes++;
361    }
362
363    jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, strlen(VolName)+1);
364    strcpy(jcr->VolumeName, VolName);
365    if (!acquire_device_for_read(jcr, dev, block)) {
366       Emsg0(M_ERROR, 0, dev->errmsg);
367       exit(1);
368    }
369
370    /* Assume that we have already read the volume label.
371     * If on second or subsequent volume, adjust buffer pointer 
372     */
373    if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
374       Dmsg1(0, "\n\
375 Warning, this Volume is a continuation of Volume %s\n",
376                 dev->VolHdr.PrevVolName);
377    }
378  
379    for ( ;; ) {
380       DEV_RECORD *record;
381
382       if (!read_record(dev, block, rec)) {
383          uint32_t status;
384          Dmsg0(20, "!read_record()\n");
385          if (dev->state & ST_EOT) {
386             if (rec->remainder) {
387                Dmsg0(20, "Not end of record.\n");
388             }
389             Dmsg2(20, "NumVolumes=%d CurVolume=%d\n", NumVolumes, CurVolume);
390             if (NumVolumes > 1 && CurVolume < NumVolumes) {
391                p = VolName;
392                while (*p++)  
393                   { }
394                CurVolume++;
395                Dmsg1(20, "There is another volume %s.\n", p);
396                VolName = p;
397                close_dev(dev);
398                jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, 
399                      strlen(VolName)+1);
400                strcpy(jcr->VolumeName, VolName);
401                printf("Mount Volume %s on device %s and press return when ready.",
402                   VolName, infname);
403                getchar();   
404                if (!ready_dev_for_read(jcr, dev, block)) {
405                   Emsg2(M_ABORT, 0, "Cannot open Dev=%s, Vol=%s\n", infname, VolName);
406                }
407                record = new_record();
408                read_record(dev, block, record); /* read vol label */
409                dump_label_record(dev, record, verbose);
410                free_record(record);
411                continue;
412             }
413             printf("End of Device reached.\n");
414             break;
415          }
416          if (dev->state & ST_EOF) {
417             Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
418             Dmsg0(20, "read_record got eof. try again\n");
419             continue;
420          }
421          if (dev->state & ST_SHORT) {
422             Emsg0(M_INFO, 0, dev->errmsg);
423             continue;
424          }
425          Emsg0(M_ERROR, 0, dev->errmsg);
426          status_dev(dev, &status);
427          Dmsg1(20, "Device status: %x\n", status);
428          if (status & MT_EOD)
429             Emsg0(M_ABORT, 0, "Unexpected End of Data\n");
430          else if (status & MT_EOT)
431             Emsg0(M_ABORT, 0, "Unexpected End of Tape\n");
432          else if (status & MT_EOF)
433             Emsg0(M_ABORT, 0, "Unexpected End of File\n");
434          else if (status & MT_DR_OPEN)
435             Emsg0(M_ABORT, 0, "Tape Door is Open\n");
436          else if (!(status & MT_ONLINE))
437             Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n");
438          else
439             Emsg2(M_ABORT, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno));
440          break;
441       }
442
443       if (debug_level >= 30) {
444          Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
445                FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream), 
446                rec->data_len);
447       }
448
449
450       /*  
451        * Check for End of File record (all zeros)
452        *    NOTE: this no longer exists
453        */
454       if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
455          Emsg0(M_ABORT, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n");
456       }
457
458       /* 
459        * Check for Start or End of Session Record 
460        *
461        */
462       if (rec->FileIndex < 0) {
463          dump_label_record(dev, rec, verbose);
464          continue;
465       }
466    }
467    term_dev(dev);
468    free_record(rec);
469    free_block(block);
470    free_jcr(jcr);
471    return;
472 }
473
474 /* Do an ls type listing of an archive */
475 static void do_ls(char *infname)
476 {
477    char fname[1000];
478    char Vol[2000];
479    char *VolName;
480    char *p;
481    struct stat statp;
482    int type;
483    long record_file_index;
484    DEV_RECORD *rec;
485    DEV_BLOCK *block;
486    int NumVolumes, CurVolume;
487    JCR *jcr;
488
489    jcr = new_jcr(sizeof(JCR), my_free_jcr);
490    VolName = Vol;
491    VolName[0] = 0;
492    if (strncmp(infname, "/dev/", 5) != 0) {
493       /* Try stripping file part */
494       p = infname + strlen(infname);
495       while (p >= infname && *p != '/')
496          p--;
497       if (*p == '/') {
498          strcpy(VolName, p+1);
499          *p = 0;
500       }
501    }
502    Dmsg2(10, "Device=%s, Vol=%s.\n", infname, VolName);
503    dev = init_dev(NULL, infname);
504    if (!dev) {
505       Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
506    }
507    /* ***FIXME**** init capabilities */
508    if (!open_device(dev)) {
509       Emsg1(M_ERROR, 0, "Cannot open %s\n", infname);
510       exit(1);
511    }
512    Dmsg0(90, "Device opened for read.\n");
513
514    rec = new_record();
515    block = new_block(dev);
516
517    NumVolumes = 0;
518    CurVolume = 1;
519    for (p = VolName; p && *p; ) {
520       p = strchr(p, '^');
521       if (p) {
522          *p++ = 0;
523       }
524       NumVolumes++;
525    }
526
527    jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, strlen(VolName)+1);
528    strcpy(jcr->VolumeName, VolName);
529    if (!acquire_device_for_read(jcr, dev, block)) {
530       Emsg0(M_ERROR, 0, dev->errmsg);
531       exit(1);
532    }
533
534    if (dump_label) {
535       dump_volume_label(dev);
536       term_dev(dev);
537       free_record(rec);
538       free_block(block);
539       return;
540    }
541
542    /* Assume that we have already read the volume label.
543     * If on second or subsequent volume, adjust buffer pointer 
544     */
545    if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
546       Dmsg1(0, "\n\
547 Warning, this Volume is a continuation of Volume %s\n",
548                 dev->VolHdr.PrevVolName);
549    }
550  
551    for ( ;; ) {
552       DEV_RECORD *record;
553
554       if (!read_record(dev, block, rec)) {
555          uint32_t status;
556          Dmsg0(20, "!read_record()\n");
557          if (dev->state & ST_EOT) {
558             if (rec->remainder) {
559                Dmsg0(20, "Not end of record.\n");
560             }
561             Dmsg2(20, "NumVolumes=%d CurVolume=%d\n", NumVolumes, CurVolume);
562             if (NumVolumes > 1 && CurVolume < NumVolumes) {
563                p = VolName;
564                while (*p++)  
565                   { }
566                CurVolume++;
567                Dmsg1(20, "There is another volume %s.\n", p);
568                VolName = p;
569                close_dev(dev);
570                jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, 
571                     strlen(VolName)+1);
572                strcpy(jcr->VolumeName, VolName);
573                printf("Mount Volume %s on device %s and press return when ready.",
574                   VolName, infname);
575                getchar();   
576                if (!ready_dev_for_read(jcr, dev, block)) {
577                   Emsg2(M_ABORT, 0, "Cannot open Dev=%s, Vol=%s\n", infname, VolName);
578                }
579                record = new_record();
580                read_record(dev, block, record); /* read vol label */
581                dump_label_record(dev, record, 0);
582                free_record(record);
583                continue;
584             }
585             printf("End of Device reached.\n");
586             break;
587          }
588          if (dev->state & ST_EOF) {
589             Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
590             Dmsg0(20, "read_record got eof. try again\n");
591             continue;
592          }
593          if (dev->state & ST_SHORT) {
594             Emsg0(M_INFO, 0, dev->errmsg);
595             continue;
596          }
597          Emsg0(M_ERROR, 0, dev->errmsg);
598          status_dev(dev, &status);
599          Dmsg1(20, "Device status: %x\n", status);
600          if (status & MT_EOD)
601             Emsg0(M_ABORT, 0, "Unexpected End of Data\n");
602          else if (status & MT_EOT)
603             Emsg0(M_ABORT, 0, "Unexpected End of Tape\n");
604          else if (status & MT_EOF)
605             Emsg0(M_ABORT, 0, "Unexpected End of File\n");
606          else if (status & MT_DR_OPEN)
607             Emsg0(M_ABORT, 0, "Tape Door is Open\n");
608          else if (!(status & MT_ONLINE))
609             Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n");
610          else
611             Emsg2(M_ABORT, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno));
612          break;
613       }
614
615       if (debug_level >= 30) {
616          Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
617                FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream), 
618                rec->data_len);
619       }
620
621
622       /*  
623        * Check for End of File record (all zeros)
624        *    NOTE: this no longer exists
625        */
626       if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
627          Emsg0(M_ABORT, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n");
628       }
629
630       /* 
631        * Check for Start or End of Session Record 
632        *
633        */
634       if (rec->FileIndex < 0) {
635          dump_label_record(dev, rec, 0);
636          continue;
637       }
638
639       /* File Attributes stream */
640       if (rec->Stream == STREAM_UNIX_ATTRIBUTES) {
641          char *ap;
642          sscanf(rec->data, "%ld %d %s", &record_file_index, &type, fname);
643          if (record_file_index != rec->FileIndex) {
644             Emsg2(M_ABORT, 0, "Record header file index %ld not equal record index %ld\n",
645                rec->FileIndex, record_file_index);
646          }
647          ap = rec->data;
648          /* Skip to attributes */
649          while (*ap++ != 0)
650             ;
651          decode_stat(ap, &statp);
652          /* Skip to link name */  
653          while (*ap++ != 0)
654             ;
655          print_ls_output(fname, ap, type, &statp);
656       }
657    }
658    term_dev(dev);
659    free_record(rec);
660    free_block(block);
661    free_jcr(jcr);
662    return;
663 }
664
665 extern char *getuser(uid_t uid);
666 extern char *getgroup(gid_t gid);
667
668 static void print_ls_output(char *fname, char *link, int type, struct stat *statp)
669 {
670    char buf[1000]; 
671    char *p, *f;
672    int n;
673
674    if (!file_is_included(&ff, fname) || file_is_excluded(&ff, fname)) {
675       return;
676    }
677    p = encode_mode(statp->st_mode, buf);
678    n = sprintf(p, "  %2d ", (uint32_t)statp->st_nlink);
679    p += n;
680    n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid));
681    p += n;
682    n = sprintf(p, "%8" lld " ", (uint64_t)statp->st_size);
683    p += n;
684    p = encode_time(statp->st_ctime, p);
685    *p++ = ' ';
686    *p++ = ' ';
687    /* Copy file name */
688    for (f=fname; *f; )
689       *p++ = *f++;
690    if (type == FT_DIR) {
691       *p++ = '/';
692    }
693    if (type == FT_LNK) {
694       *p++ = ' ';
695       *p++ = '-';
696       *p++ = '>';
697       *p++ = ' ';
698       /* Copy link name */
699       for (f=link; *f; )
700          *p++ = *f++;
701    }
702    *p++ = '\n';
703    *p = 0;
704    fputs(buf, stdout);
705 }