]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/btape.c
FSF to file on restore
[bacula/bacula] / bacula / src / stored / btape.c
1 /*
2  *
3  *   Bacula Tape manipulation program
4  *
5  *    Has various tape manipulation commands -- mostly for
6  *    use in determining how tapes really work.
7  *
8  *     Kern Sibbald, April MM
9  *
10  *   Note, this program reads stored.conf, and will only
11  *     talk to devices that are configured.
12  *
13  *   Version $Id$
14  *
15  */
16 /*
17    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
18
19    This program is free software; you can redistribute it and/or
20    modify it under the terms of the GNU General Public License as
21    published by the Free Software Foundation; either version 2 of
22    the License, or (at your option) any later version.
23
24    This program is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27    General Public License for more details.
28
29    You should have received a copy of the GNU General Public
30    License along with this program; if not, write to the Free
31    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
32    MA 02111-1307, USA.
33
34  */
35
36 #include "bacula.h"
37 #include "stored.h"
38
39
40 /* External subroutines */
41 extern void free_config_resources();
42
43 /* Exported variables */
44 int quit = 0;
45 char buf[100000];
46 int bsize = TAPE_BSIZE;
47 char VolName[100];
48
49 DEVICE *dev = NULL;
50 DEVRES *device = NULL;
51
52             
53 /* Forward referenced subroutines */
54 static void do_tape_cmds();
55 static void helpcmd();
56 static void scancmd();
57 static void rewindcmd();
58 static void clearcmd();
59 static void wrcmd();
60 static void eodcmd();
61 static void fillcmd();
62 static void unfillcmd();
63 static int flush_block(DEV_BLOCK *block, int dump);
64 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
65 static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
66
67
68 /* Static variables */
69 #define CONFIG_FILE "bacula-sd.conf"
70 char *configfile;
71
72 static BSR *bsr = NULL;
73 static char cmd[1000];
74 static int signals = TRUE;
75 static int ok;
76 static int stop;
77 static uint64_t vol_size;
78 static uint64_t VolBytes;
79 static time_t now;
80 static double kbs;
81 static long file_index;
82 static int verbose = 0;
83 static int end_of_tape = 0;
84 static uint32_t LastBlock = 0;
85 static uint32_t eot_block;
86 static uint32_t eot_block_len;
87 static uint32_t eot_FileIndex;
88 static int dumped = 0;
89
90 static char *VolumeName = NULL;
91
92 static JCR *jcr = NULL;
93
94
95 static void usage();
96 static void terminate_btape(int sig);
97 int get_cmd(char *prompt);
98
99
100 int write_dev(DEVICE *dev, char *buf, size_t len) 
101 {
102    Emsg0(M_ABORT, 0, "write_dev not implemented.\n");
103    return 0;
104 }
105
106 int read_dev(DEVICE *dev, char *buf, size_t len)
107 {
108    Emsg0(M_ABORT, 0, "read_dev not implemented.\n");
109    return 0;
110 }
111
112
113 /*********************************************************************
114  *
115  *         Main Bacula Pool Creation Program
116  *
117  */
118 int main(int argc, char *argv[])
119 {
120    int ch;
121    DEV_BLOCK *block;
122
123    /* Sanity checks */
124    if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
125       Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n",
126          TAPE_BSIZE, DEV_BSIZE);
127    }
128    if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) {
129       Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE);
130    }
131
132    printf("Tape block granularity is %d bytes.\n", TAPE_BSIZE);
133
134    working_directory = "/tmp";
135    my_name_is(argc, argv, "btape");
136    init_msg(NULL, NULL);
137
138    while ((ch = getopt(argc, argv, "b:c:d:sv?")) != -1) {
139       switch (ch) {
140          case 'b':                    /* bootstrap file */
141             bsr = parse_bsr(NULL, optarg);
142 //          dump_bsr(bsr);
143             break;
144
145          case 'c':                    /* specify config file */
146             if (configfile != NULL) {
147                free(configfile);
148             }
149             configfile = bstrdup(optarg);
150             break;
151
152          case 'd':                    /* set debug level */
153             debug_level = atoi(optarg);
154             if (debug_level <= 0) {
155                debug_level = 1; 
156             }
157             break;
158
159          case 's':
160             signals = FALSE;
161             break;
162
163          case 'v':
164             verbose++;
165             break;
166
167          case '?':
168          default:
169             helpcmd();
170             exit(0);
171
172       }  
173    }
174    argc -= optind;
175    argv += optind;
176
177
178    
179    if (signals) {
180       init_signals(terminate_btape);
181    }
182
183    if (configfile == NULL) {
184       configfile = bstrdup(CONFIG_FILE);
185    }
186
187    daemon_start_time = time(NULL);
188
189    parse_config(configfile);
190
191
192    /* See if we can open a device */
193    if (argc == 0) {
194       Pmsg0(000, "No archive name specified.\n");
195       usage();
196       exit(1);
197    } else if (argc != 1) {
198       Pmsg0(000, "Improper number of arguments specified.\n");
199       usage();
200       exit(1);
201    }
202
203    jcr = setup_jcr("btape", argv[0], bsr);
204    dev = setup_to_access_device(jcr, 0);     /* acquire for write */
205    if (!dev) {
206       exit(1);
207    }
208    block = new_block(dev);
209    lock_device(dev);
210    if (!(dev->state & ST_OPENED)) {
211       Dmsg0(129, "Opening device.\n");
212       if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) {
213          Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
214          unlock_device(dev);
215          free_block(block);
216          goto terminate;
217       }
218    }
219    Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
220    unlock_device(dev);
221    free_block(block);
222
223    Dmsg0(200, "Do tape commands\n");
224    do_tape_cmds();
225   
226 terminate:
227    terminate_btape(0);
228    return 0;
229 }
230
231 static void terminate_btape(int stat)
232 {
233
234    sm_check(__FILE__, __LINE__, False);
235    if (configfile) {
236       free(configfile);
237    }
238    free_config_resources();
239
240    if (dev) {
241       term_dev(dev);
242    }
243
244    if (debug_level > 10)
245       print_memory_pool_stats(); 
246
247    free_jcr(jcr);
248    jcr = NULL;
249
250    if (bsr) {
251       free_bsr(bsr);
252    }
253
254    term_msg();
255    close_memory_pool();               /* free memory in pool */
256
257    sm_dump(False);
258    exit(stat);
259 }
260
261 void quitcmd()
262 {
263    quit = 1;
264 }
265
266 /*
267  * Write a label to the tape   
268  */
269 static void labelcmd()
270 {
271    DEVRES *device;
272    int found = 0;
273
274    LockRes();
275    for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
276       if (strcmp(device->device_name, dev->dev_name) == 0) {
277          jcr->device = device;        /* Arggg a bit of duplication here */
278          device->dev = dev;
279          dev->device = device;
280          found = 1;
281          break;
282       }
283    } 
284    UnlockRes();
285    if (!found) {
286       Pmsg2(0, "Could not find device %s in %s\n", dev->dev_name, configfile);
287       return;
288    }
289
290    if (VolumeName) {
291       strcpy(cmd, VolumeName);
292    } else {
293       if (!get_cmd("Enter Volume Name: ")) {
294          return;
295       }
296    }
297          
298    if (!(dev->state & ST_OPENED)) {
299       if (!open_device(dev)) {
300          Pmsg1(0, "Device open failed. ERR=%s\n", strerror_dev(dev));
301       }
302    }
303    write_volume_label_to_dev(jcr, device, cmd, "Default");
304 }
305
306 /*
307  * Read the tape label   
308  */
309 static void readlabelcmd()
310 {
311    int save_debug_level = debug_level;
312    int stat;
313    DEV_BLOCK *block;
314
315    block = new_block(dev);
316    stat = read_dev_volume_label(jcr, dev, block);
317    switch (stat) {
318       case VOL_NO_LABEL:
319          Pmsg0(0, "Volume has no label.\n");
320          break;
321       case VOL_OK:
322          Pmsg0(0, "Volume label read correctly.\n");
323          break;
324       case VOL_IO_ERROR:
325          Pmsg1(0, "I/O error on device: ERR=%s", strerror_dev(dev));
326          break;
327       case VOL_NAME_ERROR:
328          Pmsg0(0, "Volume name error\n");
329          break;
330       case VOL_CREATE_ERROR:
331          Pmsg1(0, "Error creating label. ERR=%s", strerror_dev(dev));
332          break;
333       case VOL_VERSION_ERROR:
334          Pmsg0(0, "Volume version error.\n");
335          break;
336       case VOL_LABEL_ERROR:
337          Pmsg0(0, "Bad Volume label type.\n");
338          break;
339       default:
340          Pmsg0(0, "Unknown error.\n");
341          break;
342    }
343
344    debug_level = 20;
345    dump_volume_label(dev); 
346    debug_level = save_debug_level;
347    free_block(block);
348 }
349
350
351 /*
352  * Load the tape should have prevously been taken
353  * off line, otherwise this command is not necessary.
354  */
355 static void loadcmd()
356 {
357
358    if (!load_dev(dev)) {
359       Pmsg1(0, "Bad status from load. ERR=%s\n", strerror_dev(dev));
360    } else
361       Pmsg1(0, "Loaded %s\n", dev_name(dev));
362 }
363
364 /*
365  * Rewind the tape.   
366  */
367 static void rewindcmd()
368 {
369    if (!rewind_dev(dev)) {
370       Pmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
371       clrerror_dev(dev, -1);
372    } else {
373       Pmsg1(0, "Rewound %s\n", dev_name(dev));
374    }
375 }
376
377 /*
378  * Clear any tape error   
379  */
380 static void clearcmd()
381 {
382    clrerror_dev(dev, -1);
383 }
384
385 /*
386  * Write and end of file on the tape   
387  */
388 static void weofcmd()
389 {
390    int stat;
391
392    if ((stat = weof_dev(dev, 1)) < 0) {
393       Pmsg2(0, "Bad status from weof %d. ERR=%s\n", stat, strerror_dev(dev));
394       return;
395    } else {
396       Pmsg1(0, "Wrote EOF to %s\n", dev_name(dev));
397    }
398 }
399
400
401 /* Go to the end of the medium -- raw command   
402  * The idea was orginally that the end of the Bacula
403  * medium would be flagged differently. This is not
404  * currently the case. So, this is identical to the
405  * eodcmd().
406  */
407 static void eomcmd()
408 {
409    if (!eod_dev(dev)) {
410       Pmsg1(0, _("Bad status from eod. ERR=%s\n"), strerror_dev(dev));
411       return;
412    } else {
413       Pmsg0(0, _("Moved to end of media\n"));
414    }
415 }
416
417 /*
418  * Go to the end of the media (either hardware determined
419  *  or defined by two eofs.
420  */
421 static void eodcmd()
422 {
423    eomcmd();
424 }
425
426 /*
427  * Backspace file   
428  */
429 static void bsfcmd()
430 {
431    int stat;
432
433    if ((stat=bsf_dev(dev, 1)) < 0) {
434       Pmsg1(0, _("Bad status from bsf. ERR=%s\n"), strerror(errno));
435    } else {
436       Pmsg0(0, _("Back spaced one file.\n"));
437    }
438 }
439
440 /*
441  * Backspace record   
442  */
443 static void bsrcmd()
444 {
445    int stat;
446
447    if ((stat=bsr_dev(dev, 1)) < 0) {
448       Pmsg1(0, _("Bad status from bsr. ERR=%s\n"), strerror(errno));
449    } else {
450       Pmsg0(0, _("Back spaced one record.\n"));
451    }
452 }
453
454 /*
455  * List device capabilities as defined in the 
456  *  stored.conf file.
457  */
458 static void capcmd()
459 {
460    printf(_("Device capabilities:\n"));
461    printf("%sEOF ", dev->capabilities & CAP_EOF ? "" : "!");
462    printf("%sBSR ", dev->capabilities & CAP_BSR ? "" : "!");
463    printf("%sBSF ", dev->capabilities & CAP_BSF ? "" : "!");
464    printf("%sFSR ", dev->capabilities & CAP_FSR ? "" : "!");
465    printf("%sFSF ", dev->capabilities & CAP_FSF ? "" : "!");
466    printf("%sEOM ", dev->capabilities & CAP_EOM ? "" : "!");
467    printf("%sREM ", dev->capabilities & CAP_REM ? "" : "!");
468    printf("%sRACCESS ", dev->capabilities & CAP_RACCESS ? "" : "!");
469    printf("%sAUTOMOUNT ", dev->capabilities & CAP_AUTOMOUNT ? "" : "!");
470    printf("%sLABEL ", dev->capabilities & CAP_LABEL ? "" : "!");
471    printf("%sANONVOLS ", dev->capabilities & CAP_ANONVOLS ? "" : "!");
472    printf("%sALWAYSOPEN ", dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
473    printf("\n");
474
475    printf(_("Device status:\n"));
476    printf("%sOPENED ", dev->state & ST_OPENED ? "" : "!");
477    printf("%sTAPE ", dev->state & ST_TAPE ? "" : "!");
478    printf("%sLABEL ", dev->state & ST_LABEL ? "" : "!");
479    printf("%sMALLOC ", dev->state & ST_MALLOC ? "" : "!");
480    printf("%sAPPEND ", dev->state & ST_APPEND ? "" : "!");
481    printf("%sREAD ", dev->state & ST_READ ? "" : "!");
482    printf("%sEOT ", dev->state & ST_EOT ? "" : "!");
483    printf("%sWEOT ", dev->state & ST_WEOT ? "" : "!");
484    printf("%sEOF ", dev->state & ST_EOF ? "" : "!");
485    printf("%sNEXTVOL ", dev->state & ST_NEXTVOL ? "" : "!");
486    printf("%sSHORT ", dev->state & ST_SHORT ? "" : "!");
487    printf("\n");
488
489 }
490
491 /*
492  * Test writting larger and larger records.  
493  * This is a torture test for records.
494  */
495 static void rectestcmd()
496 {
497    DEV_BLOCK *block;
498    DEV_RECORD *rec;
499    int i, blkno = 0;
500
501    Pmsg0(0, "Test writting larger and larger records.\n\
502 This is a torture test for records.\nI am going to write\n\
503 larger and larger records. It will stop when the record size\n\
504 plus the header exceeds the block size (by default about 64K\n");
505
506
507    get_cmd("Do you want to continue? (y/n): ");
508    if (cmd[0] != 'y') {
509       Pmsg0(000, "Command aborted.\n");
510       return;
511    }
512
513    sm_check(__FILE__, __LINE__, False);
514    block = new_block(dev);
515    rec = new_record();
516
517    for (i=1; i<500000; i++) {
518       rec->data = check_pool_memory_size(rec->data, i);
519       memset(rec->data, i & 0xFF, i);
520       rec->data_len = i;
521       sm_check(__FILE__, __LINE__, False);
522       if (write_record_to_block(block, rec)) {
523          empty_block(block);
524          blkno++;
525          Pmsg2(0, "Block %d i=%d\n", blkno, i);
526       } else {
527          break;
528       }
529       sm_check(__FILE__, __LINE__, False);
530    }
531    free_record(rec);
532    free_block(block);
533    sm_check(__FILE__, __LINE__, False);
534 }
535
536 /* 
537  * This is a general test of Bacula's functions
538  *   needed to read and write the tape.
539  */
540 static void testcmd()
541 {
542    Pmsg0(0, "Append files test.\n\n\
543 I'm going to write one record  in file 0,\n\
544                    two records in file 1,\n\
545              and three records in file 2\n\n");
546    rewindcmd();
547    wrcmd();
548    weofcmd();      /* end file 0 */
549    wrcmd();
550    wrcmd();
551    weofcmd();      /* end file 1 */
552    wrcmd();
553    wrcmd();
554    wrcmd();
555    weofcmd();     /* end file 2 */
556 //   weofcmd();
557    rewindcmd();
558    Pmsg0(0, "Now moving to end of media.\n");
559    eodcmd();
560    Pmsg2(0, "End Append files test.\n\
561 We should be in file 3. I am at file %d. This is %s\n\n", 
562       dev->file, dev->file == 3 ? "correct!" : "NOT correct!!!!");
563
564    Pmsg0(0, "\nNow I am going to attempt to append to the tape.\n");
565    wrcmd(); 
566    weofcmd();
567 //   weofcmd();
568    rewindcmd();
569    scancmd();
570    Pmsg0(0, "End Append to the tape test.\n\
571 The above scan should have four files of:\n\
572 One record, two records, three records, and one record respectively.\n\n");
573
574
575    Pmsg0(0, "Append block test.\n\
576 I'm going to write a block, an EOF, rewind, go to EOM,\n\
577 then backspace over the EOF and attempt to append a second\n\
578 block in the first file.\n\n");
579    rewindcmd();
580    wrcmd();
581    weofcmd();
582 //   weofcmd();
583    rewindcmd();
584    eodcmd();
585    Pmsg2(0, "We should be at file 1. I am at EOM File=%d. This is %s\n",
586       dev->file, dev->file == 1 ? "correct!" : "NOT correct!!!!");
587    Pmsg0(0, "Doing backspace file.\n");
588    bsfcmd();
589    Pmsg0(0, "Write second block, hoping to append to first file.\n");
590    wrcmd();
591    weofcmd();
592    rewindcmd();
593    Pmsg0(0, "Done writing, scanning results\n");
594    scancmd();
595    Pmsg0(0, "The above should have one file of two blocks.\n");
596 }
597
598
599 static void fsfcmd()
600 {
601    int stat;
602
603    if ((stat=fsf_dev(dev, 1)) < 0) {
604       Pmsg2(0, "Bad status from fsf %d. ERR=%s\n", stat, strerror_dev(dev));
605       return;
606    }
607    Pmsg0(0, "Forward spaced one file.\n");
608 }
609
610 static void fsrcmd()
611 {
612    int stat;
613
614    if ((stat=fsr_dev(dev, 1)) < 0) {
615       Pmsg2(0, "Bad status from fsr %d. ERR=%s\n", stat, strerror_dev(dev));
616       return;
617    }
618    Pmsg0(0, "Forward spaced one record.\n");
619 }
620
621 static void rdcmd()
622 {
623 #ifdef xxxxx
624    int stat;
625
626    if (!read_dev(dev, buf, 512*126)) {
627       Pmsg1(0, "Bad status from read. ERR=%s\n", strerror_dev(dev));
628       return;
629    }
630    Pmsg1(10, "Read %d bytes\n", stat);
631 #else
632    printf("Rdcmd no longer implemented.\n");
633 #endif
634 }
635
636
637 static void wrcmd()
638 {
639    DEV_BLOCK *block;
640    DEV_RECORD *rec;
641    int i;
642
643    sm_check(__FILE__, __LINE__, False);
644    block = new_block(dev);
645    rec = new_record();
646    dump_block(block, "test");
647
648    i = block->buf_len - 100;
649    ASSERT (i > 0);
650    rec->data = check_pool_memory_size(rec->data, i);
651    memset(rec->data, i & 0xFF, i);
652    rec->data_len = i;
653    sm_check(__FILE__, __LINE__, False);
654    if (!write_record_to_block(block, rec)) {
655       Pmsg0(0, "Error writing record to block.\n"); 
656       goto bail_out;
657    }
658    if (!write_block_to_dev(dev, block)) {
659       Pmsg0(0, "Error writing block to device.\n"); 
660       goto bail_out;
661    } else {
662       Pmsg1(0, "Wrote one record of %d bytes.\n",
663          ((i+TAPE_BSIZE-1)/TAPE_BSIZE) * TAPE_BSIZE);
664    }
665    Pmsg0(0, "Wrote block to device.\n");
666
667 bail_out:
668    sm_check(__FILE__, __LINE__, False);
669    free_record(rec);
670    free_block(block);
671    sm_check(__FILE__, __LINE__, False);
672 }
673
674
675 /*
676  * Scan tape by reading block by block. Report what is
677  * on the tape.
678  */
679 static void scancmd()
680 {
681    int stat;
682    int blocks, tot_blocks, tot_files;
683    int block_size;
684    uint64_t bytes;
685
686
687    blocks = block_size = tot_blocks = 0;
688    bytes = 0;
689    if (dev->state & ST_EOT) {
690       Pmsg0(0, "End of tape\n");
691       return; 
692    }
693    update_pos_dev(dev);
694    tot_files = dev->file;
695    for (;;) {
696       if ((stat = read(dev->fd, buf, sizeof(buf))) < 0) {
697          clrerror_dev(dev, -1);
698          Mmsg2(&dev->errmsg, "read error on %s. ERR=%s.\n",
699             dev->dev_name, strerror(dev->dev_errno));
700          Pmsg2(0, "Bad status from read %d. ERR=%s\n", stat, strerror_dev(dev));
701          if (blocks > 0)
702             printf("%d block%s of %d bytes in file %d\n",        
703                     blocks, blocks>1?"s":"", block_size, dev->file);
704          return;
705       }
706       Dmsg1(200, "read status = %d\n", stat);
707 /*    sleep(1); */
708       if (stat != block_size) {
709          update_pos_dev(dev);
710          if (blocks > 0) {
711             printf("%d block%s of %d bytes in file %d\n", 
712                  blocks, blocks>1?"s":"", block_size, dev->file);
713             blocks = 0;
714          }
715          block_size = stat;
716       }
717       if (stat == 0) {                /* EOF */
718          update_pos_dev(dev);
719          printf("End of File mark.\n");
720          /* Two reads of zero means end of tape */
721          if (dev->state & ST_EOF)
722             dev->state |= ST_EOT;
723          else {
724             dev->state |= ST_EOF;
725             dev->file++;
726          }
727          if (dev->state & ST_EOT) {
728             printf("End of tape\n");
729             break;
730          }
731       } else {                        /* Got data */
732          dev->state &= ~ST_EOF;
733          blocks++;
734          tot_blocks++;
735          bytes += stat;
736       }
737    }
738    update_pos_dev(dev);
739    tot_files = dev->file - tot_files;
740    printf("Total files=%d, blocks=%d, bytes = %" lld "\n", tot_files, tot_blocks, bytes);
741 }
742
743 static void statcmd()
744 {
745    int stat = 0;
746    int debug;
747    uint32_t status;
748
749    debug = debug_level;
750    debug_level = 30;
751    if (!status_dev(dev, &status)) {
752       Pmsg2(0, "Bad status from status %d. ERR=%s\n", stat, strerror_dev(dev));
753    }
754 #ifdef xxxx
755    dump_volume_label(dev);
756 #endif
757    debug_level = debug;
758 }
759
760
761 /* 
762  * First we label the tape, then we fill
763  *  it with data get a new tape and write a few blocks.
764  */                            
765 static void fillcmd()
766 {
767    DEV_RECORD rec;
768    DEV_BLOCK  *block;
769    char ec1[50];
770    char *p;
771
772    ok = TRUE;
773    stop = FALSE;
774
775    Pmsg0(000, "\n\
776 This command simulates Bacula writing to a tape.\n\
777 It command requires two blank tapes, which it\n\
778 will label and write. It will print a status approximately\n\
779 every 322 MB, and write an EOF every 3.2 GB.  When the first tape\n\
780 fills, it will ask for a second, and after writing a few \n\
781 blocks, it will stop.  Then it will begin re-reading the\n\
782 This may take a long time. I.e. hours! ...\n\n");
783
784    get_cmd("Insert a blank tape then answer. Do you wish to continue? (y/n): ");
785    if (cmd[0] != 'y') {
786       Pmsg0(000, "Command aborted.\n");
787       return;
788    }
789
790    VolumeName = "TestVolume1";
791    labelcmd();
792    VolumeName = NULL;
793
794    
795    Dmsg1(20, "Begin append device=%s\n", dev_name(dev));
796
797    block = new_block(dev);
798
799    /* 
800     * Acquire output device for writing.  Note, after acquiring a
801     *   device, we MUST release it, which is done at the end of this
802     *   subroutine.
803     */
804    Dmsg0(100, "just before acquire_device\n");
805    if (!acquire_device_for_append(jcr, dev, block)) {
806       jcr->JobStatus = JS_Cancelled;
807       free_block(block);
808       return;
809    }
810
811    Dmsg0(100, "Just after acquire_device_for_append\n");
812    /*
813     * Write Begin Session Record
814     */
815    if (!write_session_label(jcr, block, SOS_LABEL)) {
816       jcr->JobStatus = JS_Cancelled;
817       Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"),
818          strerror_dev(dev));
819       ok = FALSE;
820    }
821
822    memset(&rec, 0, sizeof(rec));
823    rec.data = get_memory(100000);     /* max record size */
824    /* 
825     * Fill write buffer with random data
826     */
827 #define REC_SIZE 32768
828    p = rec.data;
829    for (int i=0; i < REC_SIZE; ) {
830       makeSessionKey(p, NULL, 0);
831       p += 16;
832       i += 16;
833    }
834    rec.data_len = REC_SIZE;
835
836    /* 
837     * Get Data from File daemon, write to device   
838     */
839    jcr->VolFirstFile = 0;
840    time(&jcr->run_time);              /* start counting time for rates */
841    for (file_index = 0; ok && !job_cancelled(jcr); ) {
842       uint64_t *lp;
843       rec.VolSessionId = jcr->VolSessionId;
844       rec.VolSessionTime = jcr->VolSessionTime;
845       rec.FileIndex = ++file_index;
846       rec.Stream = STREAM_FILE_DATA;
847       /* Write file_index at beginning of buffer */
848       lp = (uint64_t *)rec.data;
849       *lp = (uint64_t)file_index;
850
851       Dmsg4(250, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
852          rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream, rec.FileIndex), 
853          rec.data_len);
854        
855       if (!write_record_to_block(block, &rec)) {
856          Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
857                     rec.remainder);
858
859          /* Write block to tape */
860          if (!flush_block(block, 1)) {
861             return;
862          }
863
864          /* Every 5000 blocks (approx 322MB) report where we are.
865           */
866          if ((block->BlockNumber % 5000) == 0) {
867             now = time(NULL);
868             now -= jcr->run_time;
869             if (now <= 0) {
870                now = 1;
871             }
872             kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
873             Pmsg3(000, "Wrote block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
874                edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs);
875          }
876          /* Every 50000 blocks (approx 3.2MB) write an eof.
877           */
878          if ((block->BlockNumber % 50000) == 0) {
879             Pmsg0(000, "Flush block, write EOF\n");
880             flush_block(block, 0);
881             weof_dev(dev, 1);
882             /* The weof resets the block number */
883          }
884
885          if (block->BlockNumber > 10 && stop) {      /* get out */
886             break;
887          }
888       }
889       if (!ok) {
890          Pmsg0(000, "Not OK\n");
891          break;
892       }
893       jcr->JobBytes += rec.data_len;   /* increment bytes this job */
894       Dmsg4(190, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
895          FI_to_ascii(rec.FileIndex), rec.VolSessionId, 
896          stream_to_ascii(rec.Stream, rec.FileIndex), rec.data_len);
897    }
898    Dmsg0(000, "Write_end_session_label()\n");
899    /* Create Job status for end of session label */
900    if (!job_cancelled(jcr) && ok) {
901       jcr->JobStatus = JS_Terminated;
902    } else if (!ok) {
903       jcr->JobStatus = JS_ErrorTerminated;
904    }
905    if (!write_session_label(jcr, block, EOS_LABEL)) {
906       Pmsg1(000, _("Error writting end session label. ERR=%s\n"), strerror_dev(dev));
907       ok = FALSE;
908    }
909    /* Write out final block of this session */
910    if (!write_block_to_device(jcr, dev, block)) {
911       Pmsg0(000, "Set ok=FALSE after write_block_to_device.\n");
912       ok = FALSE;
913    }
914
915    /* Release the device */
916    if (!release_device(jcr, dev)) {
917       Pmsg0(000, "Error in release_device\n");
918       ok = FALSE;
919    }
920
921    free_block(block);
922    free_memory(rec.data);
923    Pmsg0(000, "Done with fill command. Now beginning re-read of tapes...\n");
924
925    unfillcmd();
926 }
927
928 /*
929  * Read two tapes written by the "fill" command and ensure
930  *  that the data is valid.
931  */
932 static void unfillcmd()
933 {
934    DEV_BLOCK *block;
935
936    dumped = 0;
937    VolBytes = 0;
938    LastBlock = 0;
939    block = new_block(dev);
940
941    dev->capabilities |= CAP_ANONVOLS; /* allow reading any volume */
942    dev->capabilities &= ~CAP_LABEL;   /* don't label anything here */
943
944    end_of_tape = 0;
945    get_cmd("Mount first of two tapes. Press enter when ready: "); 
946    
947    free_vol_list(jcr);
948    pm_strcpy(&jcr->VolumeName, "TestVolume1");
949    jcr->bsr = NULL;
950    create_vol_list(jcr);
951    close_dev(dev);
952    dev->state &= ~ST_READ;
953    if (!acquire_device_for_read(jcr, dev, block)) {
954       Pmsg0(000, dev->errmsg);
955       return;
956    }
957
958    time(&jcr->run_time);              /* start counting time for rates */
959    stop = 0;
960    file_index = 0;
961    read_records(jcr, dev, record_cb, my_mount_next_read_volume);
962    free_block(block);
963
964    Pmsg0(000, "Done with unfillcmd.\n");
965 }
966
967
968 /* 
969  * We are called here from "unfill" for each record on the
970  *   tape.
971  */
972 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
973 {
974
975    SESSION_LABEL label;
976    if (stop > 1) {                    /* on second tape */
977       Pmsg4(000, "Blk: FileIndex=%d: block=%u size=%d vol=%s\n", 
978            rec->FileIndex, block->BlockNumber, block->block_len, dev->VolHdr.VolName);
979       Pmsg6(000, "   Rec: VId=%d VT=%d FI=%s Strm=%s len=%d state=%x\n",
980            rec->VolSessionId, rec->VolSessionTime, 
981            FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream, rec->FileIndex),
982            rec->data_len, rec->state);
983
984       if (!dumped) {
985          dumped = 1;
986          dump_block(block, "Block not written to previous tape");
987       }
988    }
989    if (rec->FileIndex < 0) {
990       if (verbose > 1) {
991          dump_label_record(dev, rec, 1);
992       }
993       switch (rec->FileIndex) {
994          case PRE_LABEL:
995             Pmsg0(000, "Volume is prelabeled. This tape cannot be scanned.\n");
996             return;
997          case VOL_LABEL:
998             unser_volume_label(dev, rec);
999             Pmsg3(000, "VOL_LABEL: block=%u size=%d vol=%s\n", block->BlockNumber, 
1000                block->block_len, dev->VolHdr.VolName);
1001             stop++;
1002             break;
1003          case SOS_LABEL:
1004             unser_session_label(&label, rec);
1005             Pmsg1(000, "SOS_LABEL: JobId=%u\n", label.JobId);
1006             break;
1007          case EOS_LABEL:
1008             unser_session_label(&label, rec);
1009             Pmsg2(000, "EOS_LABEL: block=%u JobId=%u\n", block->BlockNumber, 
1010                label.JobId);
1011             break;
1012          case EOM_LABEL:
1013             Pmsg0(000, "EOM_LABEL:\n");
1014             break;
1015          case EOT_LABEL:              /* end of all tapes */
1016             char ec1[50];
1017
1018             if (LastBlock != block->BlockNumber) {
1019                VolBytes += block->block_len;
1020             }
1021             LastBlock = block->BlockNumber;
1022             now = time(NULL);
1023             now -= jcr->run_time;
1024             if (now <= 0) {
1025                now = 1;
1026             }
1027             kbs = (double)VolBytes / (1000 * now);
1028             Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
1029                      edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
1030
1031             Pmsg0(000, "End of all tapes.\n");
1032
1033             break;
1034          default:
1035             break;
1036       }
1037       return;
1038    }
1039    if (LastBlock != block->BlockNumber) {
1040       VolBytes += block->block_len;
1041    }
1042    if ((block->BlockNumber != LastBlock) && (block->BlockNumber % 50000) == 0) {
1043       char ec1[50];
1044       now = time(NULL);
1045       now -= jcr->run_time;
1046       if (now <= 0) {
1047          now = 1;
1048       }
1049       kbs = (double)VolBytes / (1000 * now);
1050       Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
1051                edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
1052    }
1053    LastBlock = block->BlockNumber;
1054    if (end_of_tape) {
1055       Pmsg1(000, "End of all blocks. Block=%u\n", block->BlockNumber);
1056    }
1057 }
1058
1059
1060
1061 /*
1062  * Write current block to tape regardless of whether or
1063  *   not it is full. If the tape fills, attempt to
1064  *   acquire another tape.
1065  */
1066 static int flush_block(DEV_BLOCK *block, int dump)
1067 {
1068    char ec1[50];
1069    lock_device(dev);
1070    if (!write_block_to_dev(dev, block)) {
1071       Pmsg0(000, strerror_dev(dev));            
1072       Pmsg3(000, "Block not written: FileIndex=%u Block=%u Size=%u\n", 
1073          (unsigned)file_index, block->BlockNumber, block->block_len);
1074       if (dump) {
1075          dump_block(block, "Block not written");
1076       }
1077       if (!stop) {
1078          eot_block = block->BlockNumber;
1079          eot_block_len = block->block_len;
1080          eot_FileIndex = file_index;
1081       }
1082       now = time(NULL);
1083       now -= jcr->run_time;
1084       if (now <= 0) {
1085          now = 1;
1086       }
1087       kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
1088       vol_size = dev->VolCatInfo.VolCatBytes;
1089       Pmsg2(000, "End of tape. VolumeCapacity=%s. Write rate = %.1f KB/s\n", 
1090          edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), kbs);
1091       if (!fixup_device_block_write_error(jcr, dev, block)) {
1092          Pmsg1(000, _("Cannot fixup device error. %s\n"), strerror_dev(dev));
1093          ok = FALSE;
1094          unlock_device(dev);
1095          return 0;
1096       }
1097       stop = 1;                                                     
1098       unlock_device(dev);
1099       return 1;     /* write one more block to next tape then stop */
1100    }
1101    unlock_device(dev);
1102    return 1;
1103 }
1104
1105
1106 struct cmdstruct { char *key; void (*func)(); char *help; }; 
1107 static struct cmdstruct commands[] = {
1108  {"bsf",        bsfcmd,       "backspace file"},
1109  {"bsr",        bsrcmd,       "backspace record"},
1110  {"cap",        capcmd,       "list device capabilities"},
1111  {"clear",      clearcmd,     "clear tape errors"},
1112  {"eod",        eodcmd,       "go to end of Bacula data for append"},
1113  {"test",       testcmd,      "General test Bacula tape functions"},
1114  {"eom",        eomcmd,       "go to the physical end of medium"},
1115  {"fill",       fillcmd,      "fill tape, write onto second volume"},
1116  {"unfill",     unfillcmd,    "read filled tape"},
1117  {"fsf",        fsfcmd,       "forward space a file"},
1118  {"fsr",        fsrcmd,       "forward space a record"},
1119  {"help",       helpcmd,      "print this command"},
1120  {"label",      labelcmd,     "write a Bacula label to the tape"},
1121  {"load",       loadcmd,      "load a tape"},
1122  {"quit",       quitcmd,      "quit btape"},   
1123  {"rd",         rdcmd,        "read tape"},
1124  {"readlabel",  readlabelcmd, "read and print the Bacula tape label"},
1125  {"rectest",    rectestcmd,   "test record handling functions"},
1126  {"rewind",     rewindcmd,    "rewind the tape"},
1127  {"scan",       scancmd,      "read tape block by block to EOT and report"}, 
1128  {"status",     statcmd,      "print tape status"},
1129  {"weof",       weofcmd,      "write an EOF on the tape"},
1130  {"wr",         wrcmd,        "write a single record of 2048 bytes"}, 
1131              };
1132 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
1133
1134 static void
1135 do_tape_cmds()
1136 {
1137    unsigned int i;
1138    int found;
1139
1140    while (get_cmd("*")) {
1141       sm_check(__FILE__, __LINE__, False);
1142       found = 0;
1143       for (i=0; i<comsize; i++)       /* search for command */
1144          if (fstrsch(cmd,  commands[i].key)) {
1145             (*commands[i].func)();    /* go execute command */
1146             found = 1;
1147             break;
1148          }
1149       if (!found)
1150          Pmsg1(0, _("%s is an illegal command\n"), cmd);
1151       if (quit)
1152          break;
1153    }
1154 }
1155
1156 static void helpcmd()
1157 {
1158    unsigned int i;
1159    usage();
1160    printf(_("  Command    Description\n  =======    ===========\n"));
1161    for (i=0; i<comsize; i++)
1162       printf("  %-10s %s\n", commands[i].key, commands[i].help);
1163    printf("\n");
1164 }
1165
1166 static void usage()
1167 {
1168    fprintf(stderr, _(
1169 "\nVersion: " VERSION " (" DATE ")\n\n"
1170 "Usage: btape [-c config_file] [-d debug_level] [device_name]\n"
1171 "       -c <file>   set configuration file to file\n"
1172 "       -dnn        set debug level to nn\n"
1173 "       -s          turn off signals\n"
1174 "       -t          open the default tape device\n"
1175 "       -?          print this message.\n"  
1176 "\n"));
1177
1178 }
1179
1180 /*      
1181  * Get next input command from terminal.  This
1182  * routine is REALLY primitive, and should be enhanced
1183  * to have correct backspacing, etc.
1184  */
1185 int 
1186 get_cmd(char *prompt)
1187 {
1188    int i = 0;
1189    int ch;
1190    fprintf(stdout, prompt);
1191
1192    /* We really should turn off echoing and pretty this
1193     * up a bit.
1194     */
1195    cmd[i] = 0;
1196    while ((ch = fgetc(stdin)) != EOF) { 
1197       if (ch == '\n') {
1198          strip_trailing_junk(cmd);
1199          return 1;
1200       } else if (ch == 4 || ch == 0xd3 || ch == 0x8) {
1201          if (i > 0)
1202             cmd[--i] = 0;
1203          continue;
1204       } 
1205          
1206       cmd[i++] = ch;
1207       cmd[i] = 0;
1208    }
1209    quit = 1;
1210    return 0;
1211 }
1212
1213 /* Dummies to replace askdir.c */
1214 int     dir_get_volume_info(JCR *jcr, int writing) { return 1;}
1215 int     dir_find_next_appendable_volume(JCR *jcr) { return 1;}
1216 int     dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
1217 int     dir_create_jobmedia_record(JCR *jcr) { return 1; }
1218 int     dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
1219 int     dir_send_job_status(JCR *jcr) {return 1;}
1220
1221
1222 int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
1223 {
1224    Pmsg0(000, dev->errmsg);           /* print reason */
1225    fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
1226       jcr->VolumeName, dev_name(dev));
1227    getchar();   
1228    return 1;
1229 }
1230
1231 int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev)
1232 {
1233    fprintf(stderr, "Mount next Volume on device %s and press return when ready: ",
1234       dev_name(dev));
1235    getchar();   
1236    VolumeName = "TestVolume2";
1237    labelcmd();
1238    VolumeName = NULL;
1239    return 1;
1240 }
1241
1242 static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
1243 {
1244    char ec1[50];
1245
1246    Pmsg1(000, "End of Volume \"%s\"\n", jcr->VolumeName);
1247
1248    if (LastBlock != block->BlockNumber) {
1249       VolBytes += block->block_len;
1250    }
1251    LastBlock = block->BlockNumber;
1252    now = time(NULL);
1253    now -= jcr->run_time;
1254    if (now <= 0) {
1255       now = 1;
1256    }
1257    kbs = (double)VolBytes / (1000 * now);
1258    Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
1259             edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
1260
1261    if (strcmp(jcr->VolumeName, "TestVolume2") == 0) {
1262       end_of_tape = 1;
1263       return 0;
1264    }
1265
1266    free_vol_list(jcr);
1267    pm_strcpy(&jcr->VolumeName, "TestVolume2");
1268    jcr->bsr = NULL;
1269    create_vol_list(jcr);
1270    close_dev(dev);
1271    dev->state &= ~ST_READ; 
1272    if (!acquire_device_for_read(jcr, dev, block)) {
1273       Pmsg2(0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), jcr->VolumeName);
1274       return 0;
1275    }
1276    return 1;                       /* next volume mounted */
1277 }